简体   繁体   中英

How to speed up Winforms ListView item removal?

I already use listView.BeginUpdate() and listView.EndUpdate() , but it still takes like 10 seconds when I delete for example 100 items out of 25k.

Any ideas, tricks to make it faster?

EDIT:

this.listView.BeginUpdate();
for (int i = this.listView.CheckedItems.Count - 1; i > -1; --i)
{
    this.listView.CheckedItems[i].Remove();
}
this.listView.EndUpdate();

You can start your optimizations from here:

List<int> toRemove = new List<int>();

foreach (ListViewItem item in this.listView.Items)
{
    if (item.Checked) // check other remove conditions here
        toRemove.Add(item.Index);
}

/* sort indices descending, so you'll remove items with higher indices first
   and they will not be shifted when you remove items with lower indices */
toRemove.Sort((x, y) => y.CompareTo(x));
/* in this specific case you can simply use toRemove.Reverse(); 
   or iterate thru toRemove in reverse order
   because it is already sorted ascending.
   But you might want to force sort it descending in some other cases.
*/

this.listView.BeginUpdate();

foreach (int itemIndex in toRemove)
    this.listView.Items.RemoveAt(itemIndex); // use RemoveAt when possible. It's much faster with large collections

this.listView.EndUpdate();

The ListView will trigger an event for every single item that is removed from the list. You could try to avoid that by clearing the entire ListView and then adding at once a new list of items, which is stripped of the 100 items you wanted to remove. This would trigger only a handful of events.

That's because each time you remove element from Items, ListView has to find that item ( walking the list to do so ) and refresh CheckedItems collection (which iterates all remaining items again) so complexity is O^2.

The easiest approach is to cache SelectedIndices and use listItem.Items.RemoveAt():

var selectedIndices = listView.SelectedIndices.Cast<int>().Reverse().ToList();
listView.BeginUpdate();
foreach (var index in selectedIndices) {
    listView.Items.RemoveAt(index);
}
listView.EndUpdate();

If you don't want to use the Cast<> extension method, you can replace the first line with:

List<int> oToDelete = new List<int>(SelectedIndices.Count);
foreach (int iX in SelectedIndices)
{
   oToDelete.Add(iX);
}
oToDelete.Reverse();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM