ListView में आइटम जोड़ने की गति कैसे करें?


84

मैं WinForms ListView में कुछ हज़ार (जैसे 53,709) आइटम जोड़ रहा हूँ।

प्रयास 1 :13,870 ms

foreach (Object o in list)
{
   ListViewItem item = new ListViewItem();
   RefreshListViewItem(item, o);
   listView.Items.Add(item);
}

यह बहुत बुरी तरह से चलता है। स्पष्ट पहला फिक्स कॉल करना है BeginUpdate/EndUpdate

प्रयास 2 :3,106 ms

listView.BeginUpdate();
foreach (Object o in list)
{
   ListViewItem item = new ListViewItem();
   RefreshListViewItem(item, o);
   listView.Items.Add(item);
}
listView.EndUpdate();

यह बेहतर है, लेकिन अभी भी परिमाण का एक क्रम बहुत धीमा है। आइए ListViewItems को ListViewItems जोड़ने से अलग करें, ताकि हम वास्तविक अपराधी का पता लगा सकें:

प्रयास 3 :2,631 ms

var items = new List<ListViewItem>();
foreach (Object o in list)
{
   ListViewItem item = new ListViewItem();
   RefreshListViewItem(item, o);
   items.Add(item);
}

stopwatch.Start();

listView.BeginUpdate();
    foreach (ListViewItem item in items)
        listView.Items.Add(item));
listView.EndUpdate();

stopwatch.Stop()

असली अड़चन वस्तुओं को जोड़ रही है। चलो AddRangeएक के बजाय इसे परिवर्तित करने का प्रयास करेंforeach

प्रयास 4: 2,182 ms

listView.BeginUpdate();
listView.Items.AddRange(items.ToArray());
listView.EndUpdate();

थोड़ा - सा बेहतर। आइए सुनिश्चित करें कि टोंटी अंदर नहीं हैToArray()

प्रयास 5: 2,132 ms

ListViewItem[] arr = items.ToArray();

stopwatch.Start();

listView.BeginUpdate();
listView.Items.AddRange(arr);
listView.EndUpdate();

stopwatch.Stop();

सीमा सूची में आइटम जोड़ रही है। हो सकता है कि अन्य ओवरलोड AddRange, जहां हम ListView.ListViewItemCollectionएक सरणी के बजाय जोड़ते हैं

प्रयास 6: 2,141 ms

listView.BeginUpdate();
ListView.ListViewItemCollection lvic = new ListView.ListViewItemCollection(listView);
lvic.AddRange(arr);
listView.EndUpdate();

वैसे यह बेहतर नहीं है।

अब यह फैलने का समय है:

  • चरण 1 - सुनिश्चित करें कि कोई भी कॉलम "ऑटो-चौड़ाई" पर सेट नहीं है :

    यहां छवि विवरण दर्ज करें

    जाँच

  • चरण 2 - सुनिश्चित करें कि सूची दृश्य उन आइटमों को छाँटने की कोशिश नहीं कर रहा है जो हर बार मुझे एक जोड़ते हैं:

    यहां छवि विवरण दर्ज करें

    जाँच

  • चरण 3 - स्टैकओवरफ़्लो से पूछें:

    यहां छवि विवरण दर्ज करें

    जाँच

नोट: जाहिर है यह ListView वर्चुअल मोड में नहीं है; चूंकि आप वर्चुअल सूची दृश्य (आप सेट VirtualListSize) में आइटमों को "जोड़" नहीं सकते । सौभाग्य से मेरा प्रश्न वर्चुअल मोड में सूची दृश्य के बारे में नहीं है।

क्या मुझे कुछ याद आ रहा है जो सूची में आइटम जोड़ने के लिए इतना धीमा हो सकता है?


बोनस चटर

मुझे पता है कि विंडोज लिस्टव्यू क्लास बेहतर कर सकती है, क्योंकि मैं उस कोड को लिख सकता हूं जो इसे करता है 394 ms:

ListView1.Items.BeginUpdate;
for i := 1 to 53709 do
   ListView1.Items.Add();
ListView1.Items.EndUpdate;

जब समकक्ष C # कोड की तुलना में 1,349 ms:

listView.BeginUpdate();
for (int i = 1; i <= 53709; i++)
   listView.Items.Add(new ListViewItem());
listView.EndUpdate();

तेजी से परिमाण का एक क्रम है।

WinForms ListView आवरण की कौन सी संपत्ति मैं गायब हूँ?


2
साइड नोट: यदि आप चेकबॉक्स का उपयोग कर रहे हैं, तो आपको सूची दृश्य में जोड़ने से पहले चेक की गई स्थिति सेट करनी चाहिए। शुरु कर रहा है की जाँच की राज्यों blogs.msdn.com/b/hippietim/archive/2006/03/20/556007.aspx
टिम Schmelter

3
मुझे पूछना है: आप कई आइटम क्यों जोड़ रहे हैं?
OO

4
महान प्रश्न इयान। क्या आपने इस ब्लॉग को इस विषय पर देखा है? virtualdub.org/blog/pivot/entry.php?id=273
क्रिस शिन

2
1,349 एमएस, असंभव। मैं 53709 वस्तुओं के साथ कोशिश करता हूं जिसमें कुछ मिनट लगते हैं। इतने सारे आइटमों के साथ सूची दृश्य का उपयोग क्यों करें? , वास्तव में प्रयोग करने योग्य नहीं है। आप स्पीड बढ़ाने के लिए लिस्टबॉक्स या कॉम्बोबॉक्स का उपयोग कर सकते हैं लेकिन एक पागल नंबर है
Xilmiki

4
आभासी सूची दृश्य का उपयोग क्यों नहीं किया जाता है? ठीक है, आपको प्रोग्राम करने की आवश्यकता है कि आइटम डेटा को कैसे पुनः प्राप्त करें और आपको अन्य चीजों जैसे कि छंटाई, फ़िल्टरिंग आदि को बनाए रखना होगा, लेकिन आप सूची को तुरंत भर देंगे, चाहे कितनी भी आइटम हों।
कैस्परह

जवाबों:


22

मैंने सूची देखने के लिए स्रोत कोड पर एक नज़र डाली और मैंने कुछ चीजें देखीं जो प्रदर्शन को 4 के कारक से धीमा कर सकती हैं या इसलिए कि आप देख रहे हैं:

ListView.cs, ListViewItemsCollection.AddRangeकॉल में ListViewNativeItemCollection.AddRange, जो कि मैंने अपना ऑडिट शुरू किया था

ListViewNativeItemCollection.AddRange(लाइन से: 18120) में मूल्यों के पूरे संग्रह से दो गुजरते हैं, एक को InsertItemsकहा जाता है के बाद उन्हें 'बहाल' करने के लिए अन्य जाँच की गई वस्तुओं को इकट्ठा करने के लिए (वे दोनों एक चेक के खिलाफ पहरा देते हैं owner.IsHandleCreated, मालिक होने के नाते ListView) फिर कॉल करते हैं BeginUpdate

ListView.InsertItems(लाइन से: 12952), पहला कॉल, पूरी सूची का एक और पारगमन है फिर ArrayList.AddRange कहा जाता है (शायद वहाँ एक और पास) तो उसके बाद एक और पास। के लिए अग्रणी

ListView.InsertItems(लाइन से: 12952), दूसरी कॉल (के माध्यम से EndUpdate) एक और पास से गुजरती है जहां उन्हें जोड़ा जाता है HashTable, और Debug.Assert(!listItemsTable.ContainsKey(ItemId))यह डिबग मोड में इसे और धीमा कर देगा। यदि हैंडल नहीं बनाया गया है, तो यह आइटम को एक में जोड़ता है ArrayList, listItemsArrayलेकिन if (IsHandleCreated), फिर यह कॉल करता है

ListView.InsertItemsNative(लाइन से: 3848) अंतिम सूची से गुजरते हैं जहां इसे वास्तव में मूल सूची में जोड़ा जाता है। a Debug.Assert(this.Items.Contains(li)अतिरिक्त डिबग मोड में प्रदर्शन को धीमा कर देगा।

तो वहाँ वस्तुओं की पूरी सूची के माध्यम से अतिरिक्त पास की एक बहुत कुछ है। इससे पहले कि यह वास्तव में मूल सूची में आइटम डालने के लिए हो जाता है। हैंडल के बनाए जाने के विरुद्ध चेक द्वारा कुछ पासों की रखवाली की जाती है, इसलिए यदि आप हैंडल बनाने से पहले आइटम जोड़ सकते हैं, तो यह आपको कुछ समय बचा सकता है। OnHandleCreatedविधि लेता है listItemsArrayऔर कहता है InsertItemsNativeसभी अतिरिक्त उपद्रव के बिना सीधे।

आप ListViewकोड को संदर्भ स्रोत में स्वयं पढ़ सकते हैं और देख सकते हैं , शायद मुझे कुछ याद हो।

MSDN मैगज़ीन के मार्च 2006 के अंक में एक लेख कहा गया था Winning Forms: Practical Tips for Boosting The Performance of Windows Forms Apps

इस लेख में अन्य बातों के अलावा, सूची दृश्य के प्रदर्शन को बेहतर बनाने के लिए युक्तियां थीं। यह इंगित करता है कि संभाल से पहले आइटम जोड़ने के लिए इसका तेज़ है, लेकिन जब नियंत्रण प्रदान किया जाता है तो आप एक कीमत का भुगतान करेंगे। शायद टिप्पणियों में उल्लिखित प्रतिपादन अनुकूलन को लागू करने और संभाल से पहले आइटम जोड़ने से दोनों दुनिया का सबसे अच्छा मिलेगा।

संपादित करें: विभिन्न तरीकों से इस परिकल्पना का परीक्षण किया गया है, और हैंडल बनाने से पहले आइटमों को जोड़ते समय सूपर फास्ट है, जब यह हैंडल बनाने के लिए चला जाता है तो यह तेजी से धीमा होता है। मैंने इसे हैंडल बनाने के लिए ट्रिक करने की कोशिश के साथ खेला, फिर किसी तरह इसे सभी अतिरिक्त पास से गुजरने के बिना इसे सम्मिलित करने के लिए कॉल करें। लेकिन अफसोस कि मुझे नाकाम कर दिया गया है। केवल एक चीज जो मैं सोच सकता था कि संभव है, आपके Win32 ListView को c ++ प्रोजेक्ट में बनाना, उसे सामानों से भर देना, और उसके हैंडल को बनाते समय ListView द्वारा भेजे गए CreateWindow संदेश को कैप्चर करने के लिए हुकिंग का उपयोग करना और win32 के संदर्भ में वापस जाना। एक नई विंडो के बजाय लिस्ट व्यू .. लेकिन कौन जानता है कि इससे वहां क्या प्रभाव पड़ता है ... एक Win32 गुरु को इस पागल विचार के बारे में बोलने की आवश्यकता होगी :)


10

मैंने इस कोड का उपयोग किया है:

ResultsListView.BeginUpdate();
ResultsListView.ListViewItemSorter = null;
ResultsListView.Items.Clear();

//here we add items to listview

//adding item sorter back
ResultsListView.ListViewItemSorter = lvwColumnSorter;


ResultsListView.Sort();
ResultsListView.EndUpdate();

मैंने GenerateMemberप्रत्येक कॉलम के लिए भी गलत सेट किया है ।

कस्टम सूची दृश्य सॉर्टर से लिंक करें: http://www.codeproject.com/Articles/5332/ListView-Column-Sorter


4
हां, आइटम जोड़ते समय एक सॉर्टर सक्रिय होना *** बहुत ही धीमी गति से *** है। लेकिन इस मामले में मेरे पास सॉर्टर नहीं है। लेकिन यह उन लोगों के लिए एक उपयोगी पहला कदम है, जिन्हें यह एहसास नहीं हो सकता है कि .NET listview हर बार किसी आइटम को जोड़ने के बजाय कॉल करता है - बजाय अंत में।
इयान बॉयड

0

मेरी भी यही समस्या है। फिर मैंने पाया कि sorterयह इतना धीमा है। कुली को अशक्त बनाओ

this.listViewAbnormalList.ListViewItemSorter = null;

फिर जब सॉर्टर, ListView_ColumnClickविधि पर क्लिक करें , तो इसे बनाएं

 lv.ListViewItemSorter = new ListViewColumnSorter()

अंत में, इसे हल करने के बाद, sorterफिर से नल बना दें

 ((System.Windows.Forms.ListView)sender).Sort();
 lv.ListViewItemSorter = null;

स्लाव 2 ने सुझाव दिया कि । जो मैंने अपने मूल प्रश्न में भी सुझाया था।
इयान बॉयड

हाँ, यह ऊपर दिए गए उत्तर के समान है। :)
बटुर

-1

सूची दृश्य बॉक्स जोड़ें

यह सरल कोड है जो मैं स्तंभों से मिलकर एक सूची बॉक्स में आइटम जोड़ने के लिए निर्माण करने में सक्षम था। पहला कॉलम आइटम है जबकि दूसरा कॉलम मूल्य है। पहले कॉलम में दालचीनी के नीचे कोड और दूसरे कॉलम में 0.50।

// How to add ItemName and Item Price
listItems.Items.Add("Cinnamon").SubItems.Add("0.50");

कोई तात्कालिक आवश्यकता नहीं है।


यह एक आइटम जोड़ने का एक आसान तरीका है। लेकिन यह 75,000 वस्तुओं को जोड़ने का एक तेज़ तरीका नहीं है ।
इयान बॉयड

मैं सहमत हूँ। मैं उस ListView वर्ग को तत्काल परिणाम के साथ कई परिणाम जोड़ने के लिए एक कार्यान्वयन पोस्ट करूंगा।
डेमेट्रे Phipps

-2

अपनी सभी ListViewItems FIRST बनाएं , फिर उन्हें एक ही बार में ListView में जोड़ें ।

उदाहरण के लिए:

    var theListView = new ListView();
    var items = new ListViewItem[ 53709 ];

    for ( int i = 0 ; i < items.Length; ++i )
    {
        items[ i ] = new ListViewItem( i.ToString() );
    }

    theListView.Items.AddRange( items );
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.