2010-07-21 6 views
5

मेरे पास निम्न कोड है, जो मूल रूप से डेटाबेस से मान लेता है और एक सूचीदृश्य पॉप्युलेट करता है।.NET Listview ताज़ा करें

using (IDataReader reader = cmd.ExecuteReader()) 
{      
    lvwMyList.Items.Clear(); 
    while (reader.Read()) 
    { 
     ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString()); 
     lvi.SubItems.Add(reader["Value2"].ToString());      
    } 
} 

समस्या मेरे पास है कि इस बार बार सूचीदृश्य में मदों में कम अंतराल (हर दूसरे) और परिणाम पर निष्पादित किया जाता है लगातार गायब और फिर से दिखाई दे रहा है। क्या समीक्षा के साथ किए जाने तक रीफ्रेशिंग से सूचीदृश्य को रोकने का कोई तरीका है? नीचे की तरह कुछ:

using (IDataReader reader = cmd.ExecuteReader()) 
{      
    lvwMyList.Items.Freeze(); // Stop the listview updating 
    lvwMyList.Items.Clear(); 
    while (reader.Read()) 
    { 
     ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString()); 
     lvi.SubItems.Add(reader["Value2"].ToString());      
    } 
    lvwMyList.Items.UnFreeze(); // Refresh the listview 
} 
+0

फ्रीज का अर्थ कुछ और है: इसका मतलब है कि ऑब्जेक्ट (इस मामले में तत्वों का संग्रह) जमे हुए होने पर नहीं बदलेगा। इस मामले में आप तुरंत इसे संशोधित कर रहे हैं! –

+1

फ्रीज केवल एक शब्द था जिसे मैंने अपनी आवश्यकता को समझाने के उद्देश्य से उपयोग किया –

उत्तर

9
इस तरह

:

try 
{ 
    lvwMyList.BeginUpdate(); 
    //bla bla bla 

} 
finally 
{ 
    lvwMyList.EndUpdate(); 
} 

सुनिश्चित करें कि आप lvwMyList.Items.Clear()आह्वानBeginUpdate के बाद आप इसे भरने से पहले सूची साफ़ करना चाहते हैं सुनिश्चित करें।

+1

जब भी आप आइटम साफ़ करते हैं तो यह अभी भी 'फ्लैश' होगा। TreeView पर भी होता है। – leppie

+1

यह निश्चित रूप से करता है जो मैंने पूछा था। केवल समस्या यह है कि यह वास्तव में फॉर्म को भी लॉक करता है :-) –

+1

स्टार्टअपडेट के अंदर स्पष्ट होने से इसे चमकने से रोकना चाहिए। फॉर्म स्टार्टअपडेट द्वारा लॉक नहीं किया गया है लेकिन आपके कोड से जो नए आइटम जोड़ता है। अद्यतन करने से पहले डीबी से सभी वस्तुओं को लाने का प्रयास करें। – jgauffin

0

आप अद्यतन के दौरान दृश्यमान या सक्षम गुणों को गलत पर सेट करने का प्रयास कर सकते हैं और देख सकते हैं कि आप उन परिणामों को बेहतर तरीके से पसंद करते हैं या नहीं। बेशक, अपडेट किए जाने पर मानों को सही पर रीसेट करें।

एक और तरीका सूची बॉक्स को ओवरले करने के लिए पैनल बनाना है। इसे अपने बाएं, दाएं, ऊंचाई और चौड़ाई गुणों को अपने सूची बॉक्स के समान सेट करें और अपडेट के दौरान इसकी दृश्यमान संपत्ति को सही पर सेट करें, आपके द्वारा किए जाने के बाद गलत।

+1

नियंत्रण को अक्षम और सक्षम करने से समस्या और खराब हो जाती है –

1

यह मेरी पहली बार स्टैक ओवरफ्लो पर पोस्टिंग है, इसलिए नीचे गन्दा कोड स्वरूपण क्षमा करें।

ListView को अपडेट करते समय फ़ॉर्म को लॉक करने से रोकने के लिए, आप नीचे दी गई विधि का उपयोग कर सकते हैं जिसे मैंने इस समस्या को हल करने के लिए लिखा है।

नोट: यदि आप सूची दृश्य को 20,000 से अधिक वस्तुओं के साथ पॉप्युलेट करने की अपेक्षा करते हैं तो इस विधि का उपयोग नहीं किया जाना चाहिए। यदि आपको ListView में 20k से अधिक आइटम जोड़ने की आवश्यकता है, तो वर्चुअल मोड में ListView को चलाने पर विचार करें।

public static async void PopulateListView<T>(ListView listView, Func<T, ListViewItem> func, 
     IEnumerable<T> objects, IProgress<int> progress) where T : class, new() 
    { 
     if (listView != null && listView.IsHandleCreated) 
     { 
      var conQue = new ConcurrentQueue<ListViewItem>(); 

      // Clear the list view and refresh it 
      if (listView.InvokeRequired) 
      { 
       listView.BeginInvoke(new MethodInvoker(() => 
        { 
         listView.BeginUpdate(); 
         listView.Items.Clear(); 
         listView.Refresh(); 
         listView.EndUpdate(); 
        })); 
      } 
      else 
      { 
       listView.BeginUpdate(); 
       listView.Items.Clear(); 
       listView.Refresh(); 
       listView.EndUpdate(); 
      } 

      // Loop over the objects and call the function to generate the list view items 
      if (objects != null) 
      { 
       int objTotalCount = objects.Count(); 

       foreach (T obj in objects) 
       { 
        await Task.Run(() => 
         { 
          ListViewItem item = func.Invoke(obj); 

          if (item != null) 
           conQue.Enqueue(item); 

          if (progress != null) 
          { 
           double dProgress = ((double)conQue.Count/objTotalCount) * 100.0; 

           if(dProgress > 0) 
            progress.Report(dProgress > int.MaxValue ? int.MaxValue : (int)dProgress); 
          } 
         }); 
       } 

       // Perform a mass-add of all the list view items we created 
       if (listView.InvokeRequired) 
       { 
        listView.BeginInvoke(new MethodInvoker(() => 
         { 
          listView.BeginUpdate(); 
          listView.Items.AddRange(conQue.ToArray()); 
          listView.Sort(); 
          listView.EndUpdate(); 
         })); 
       } 
       else 
       { 
        listView.BeginUpdate(); 
        listView.Items.AddRange(conQue.ToArray()); 
        listView.Sort(); 
        listView.EndUpdate(); 
       } 
      } 
     } 

     if (progress != null) 
      progress.Report(100); 
    } 

तुम बस अशक्त का उपयोग करें और विधि बस के रूप में अच्छी तरह से काम करेगा एक IProgress वस्तु प्रदान करने के लिए नहीं है,।

नीचे विधि का एक उदाहरण उपयोग है।

सबसे पहले, उस श्रेणी को परिभाषित करें जिसमें ListViewItem के लिए डेटा शामिल है।

public class TestListViewItemClass 
{ 
    public int TestInt { get; set; } 

    public string TestString { get; set; } 

    public DateTime TestDateTime { get; set; } 

    public TimeSpan TestTimeSpan { get; set; } 

    public decimal TestDecimal { get; set; } 
} 

फिर, एक विधि बनाएं जो आपके डेटा आइटम लौटाती है। यह विधि किसी डेटाबेस से पूछताछ कर सकती है, एक वेब सेवा एपीआई, या जो कुछ भी कह सकती है, जब तक यह आपके वर्ग प्रकार का एक आईनेमरेबल लौटाती है।

public IEnumerable<TestListViewItemClass> GetItems() 
{ 
    for (int x = 0; x < 15000; x++) 
    { 
     yield return new TestListViewItemClass() 
     { 
      TestDateTime = DateTime.Now, 
      TestTimeSpan = TimeSpan.FromDays(x), 
      TestInt = new Random(DateTime.Now.Millisecond).Next(), 
      TestDecimal = (decimal)x + new Random(DateTime.Now.Millisecond).Next(), 
      TestString = "Test string " + x, 
     }; 
    } 
} 

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

मैंने उस फ़ंक्शन को शामिल किया है जो मेरी कक्षा, TestListViewItemClass के उदाहरण से ListViewItem उत्पन्न करता है। एक उत्पादन परिदृश्य में, आप शायद कहीं और फ़ंक्शन को परिभाषित करना चाहते हैं।

private async void TestListViewForm_Load(object sender, EventArgs e) 
{  
    var function = new Func<TestListViewItemClass, ListViewItem>((TestListViewItemClass x) => 
    { 
     var item = new ListViewItem(); 

     if (x != null) 
     { 
      item.Text = x.TestString; 
      item.SubItems.Add(x.TestDecimal.ToString("F4")); 
      item.SubItems.Add(x.TestDateTime.ToString("G")); 
      item.SubItems.Add(x.TestTimeSpan.ToString()); 
      item.SubItems.Add(x.TestInt.ToString()); 
      item.Tag = x; 

      return item; 
     } 

     return null; 
    }); 

     PopulateListView<TestListViewItemClass>(this.listView1, function, GetItems(), progress); 

} 

उपरोक्त उदाहरण में, मैं इस तरह के फार्म के निर्माता में एक IProgress वस्तु बनाया:

progress = new Progress<int>(value => 
{ 
    toolStripProgressBar1.Visible = true; 

    if (value >= 100) 
    { 
     toolStripProgressBar1.Visible = false; 
     toolStripProgressBar1.Value = 0; 
    } 
    else if (value > 0) 
    { 
     toolStripProgressBar1.Value = value; 
    } 
}); 

मैं परियोजनाओं में एक ListView कई बार पॉप्युलेट हम जहां तक ​​पॉप्युलेट कर रहे थे की इस पद्धति का उपयोग किया है ListView में 12,000 आइटम तक, और यह बेहद तेज़ है। मुख्य बात यह है कि आप अपडेट के लिए ListView को स्पर्श करने से पहले डेटाबेस से पूरी तरह से अपनी ऑब्जेक्ट को बनाने की आवश्यकता है।

उम्मीद है कि यह सहायक है।

मैंने विधि के एसिंक संस्करण के नीचे शामिल किया है, जो इस पोस्ट के शीर्ष पर दिखाए गए मुख्य विधि को कॉल करता है।

public static Task PopulateListViewAsync<T>(ListView listView, Func<T, ListViewItem> func, 
     IEnumerable<T> objects, IProgress<int> progress) where T : class, new() 
{ 
    return Task.Run(() => PopulateListView<T>(listView, func, objects, progress)); 
}