views:

663

answers:

6

So I have a ListView with an upper limit of about 1000 items. I need to be able to filter these items using a textbox's TextChanged event. I have some code that works well for a smaller number of items (~400), but when I need to re-display a full list of all 1000 items, it takes about 4 seconds.

I am not creating new ListViewItems every time. Instead, I keep a list of the full item collection and then add from that. It seems that the .Add method is taking a long time regardless. Here is a little sample:

this.BeginUpdate();
foreach (ListViewItem item in m_cachedItems)
{
    MyListView.Add(item);
}
this.EndUpdate;

I have tried only adding the missing items (i.e., the difference between the items currently being displayed and the total list of items), but this doesn't work either. There can be a situation in which there is only one item currently displayed, the user clears the textbox, and I need to display the entire list.

I am not very experienced in eeking performance out of .NET controls with a large sample like this, so I don't really know a better way to do it. Is there any way around using the .Add() method, or if not, just e better general solution? Thanks for any help you guys can offer in advance.

+1  A: 

There are two things to address this:

  1. Turn off sorting while manipulating the list contents.
  2. Hide the list so it doesn't try to paint.

The 1st point is the biggest performance gain in list manipulation out of these two. To achieve this, just set the ListViewItemSorter to null for the duration of the modification and set it back at the end.

For the 2nd option, I often draw the list to a bitmap and then show that bitmap in a PictureBox so the user doesn't see the list disappear, then just reshow the list when I'm done.

Jeff Yates
+3  A: 

There is a better way, you can use the VirtualMode of the list view.

That documentation should get you started. The idea is to provide information to the ListView only as it's needed. Such information is retrieved using events. All you have to do is implement those events and tell the list view how many items it contains.

Frank Krueger
This does give better performance but can be a lot more work. I suspect with a list of only a few hundred, it's easier just to disable sorting while the list is modified.
Jeff Yates
I wouldn't consider it a lot more work - just more work. Sure, the Microsoft examples make it look like a lot, but they're always ridiculous like that. :-)
Frank Krueger
Well, there's no arguing with that. :D
Jeff Yates
A: 

@ffpf: Thanks, I wasn't aware that the collection was sorting every update. The BeginUpdate() method does stop the control from painting itself during this process.

@Frank Krueger: I will definitely check that out. I have so much to learn ;)

Ed Swangren
BeginUpdate doesn't always stop the painting. These controls, underneath, are still receiving Windows messages, and I think some of them cause repaints to occur. I've experienced this with both the ListView and the TreeView, hence having to come up with the PictureBox solution.
Jeff Yates
A: 

OK, turning off sorting did the trick. Thanks a lot guys, I would choose both of your answers if I could. I had no idea about virtual mode, so I do appreciate the heads up.

Ed Swangren
A: 

Also note that you can hide items and so make them invisible without removing them. So add all your items the first time around and then later on you just hide the ones no longer needed and show the ones that are.

Phil Wright
...I had no idea. Thank you.
Ed Swangren
Actually, I didn't find a property for that at first glance. I'll look a bit harder.
Ed Swangren
I don't think this is possible, unless you owner draw the list view.
Ozgur Ozcitak
+1  A: 

AddRange is much faster than add

MyListView.AddRange(items)
sieben