यह मेरी पहली बार स्टैक ओवरफ्लो पर पोस्टिंग है, इसलिए नीचे गन्दा कोड स्वरूपण क्षमा करें।
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));
}
फ्रीज का अर्थ कुछ और है: इसका मतलब है कि ऑब्जेक्ट (इस मामले में तत्वों का संग्रह) जमे हुए होने पर नहीं बदलेगा। इस मामले में आप तुरंत इसे संशोधित कर रहे हैं! –
फ्रीज केवल एक शब्द था जिसे मैंने अपनी आवश्यकता को समझाने के उद्देश्य से उपयोग किया –