//
you're reading...
.NET 2.0, Technology

Getting along with ListView’s VirtualList mode

Coming up in .NET 2.0 the ListView control now supports virtual mode, which is used to cut down on the amount of memory used by the ListView but requires more work from the developer. It does this by raising several events when it needs some information about the items to be displayed. This post isn’t going to focus on that, but rather one aspect that may be missed when you go to use this new functionality.

Say you have just completed a drag and drop operation from your virtual ListView onto some other control which requires that you now remove those items from whatever backing store you are using.

You will probably be tempted to write code like this to remove the items.

ListView.SelectedIndexCollection indices = listView.SelectedIndices;
listView.BeginUpdate(); 
 
for( int i = indices.Count - 1; i >= 0; i-- )
    backingList.RemoveAt( indices[i] );
 
listView.VirtualListSize = backingList.Count;
listView.EndUpdate();

Just so we don’t need to do any other funky math, we work backwards through the indices so that we aren’t modifing indexes that we will be working with later. This code works fine for a moderately sized list, but combine a large list with a large number of selected items and you’ll quickly find the app slow to a crawl, two problems exists…The first is in how the SelectedIndexCollection’s indexer works…but another problem is also that we’re performing a large copy of memory every time an item is removed from the backingList.

Instead, let’s tackle this problem in another way. Rather than take out entries we don’t want, it would be faster to instead move around the items we do want. This works out better because every time we removed an entry in the first example, all entries after that had to move up by one…so if you’ve got 20,000 items to remove the first block of code was moving entries up by one 20,000 times. Now we may be moving items one at a time, but every item in the backing list will only move 0 or 1 time.

ListView.SelectedIndexCollection indices = listView.SelectedIndices;
listView.BeginUpdate(); 

if( backingList.Count == indices.Count )
{
    backingList.Clear();
}

Pretty simple so far, if all items were selected then we’ll just clear out the list…no fuss no muss — what the heck is muss anyway?

Continuing on….using comments to explain what is going on

else
{
    // Create a new backing list, with capacity equal to
    // total number of items minus the number to be removed (ie selected)
    BackingList list = new BackingList( backingList.Count - indices.Count );

    // Some local vars to store some state
    int newIndex = 0;
    int count = 0;

    // Using the index of every selected item
    foreach( int index in indices )
    {
        // Start with newIndex where we left off
        // and continue while the newIndex + count (see below)
        // is less than the index we have selected
        // And move items from the old list to the new one
        for( ; (newIndex + count) < index; newIndex++ )
        {
            list.Add( backingList[ newIndex + count ] );
        }
        // count keeps track of how many indices we've gone through already
        // We need this so that we can offset our access into the old list
        count++;
    }

    // Now, cover all items from last index to the end of the list
    for( ; ( newIndex + count ) < backingList.Count; newIndex++ )
    {
        list.Add( backingList[ newIndex + count ] );
    }

    // Assign our new backingList over the old one
    this.backingList = list;
}

listView.VirtualListSize = backingList.Count;
listView.EndUpdate();

It is possible to make this faster, but to do so you would need to mess with the array stuff yourself rather than using the handy List/ArrayList classes. Which means adding new items to your list can get messy with lots of Array.Copy’s involved. But it would mean that instead of having to loop through and add each item individually, we could do a massive memory copy operation to copy between two indices which should be much faster.

I have tested this technique with a somewhat large backingList (24,000 items, each representing a file) and it performed very well.

Advertisements

About James

I am a Senior Developer/Consultant for InfoPlanIT, LLC. I previously spent over 7 years as a Product Manager for what eventually became ComponentOne, a division of GrapeCity. While there, I helped to create ActiveReports 7, GrapeCity ActiveAnalysis, and Data Dynamics Reports.

Discussion

2 thoughts on “Getting along with ListView’s VirtualList mode

  1. “Coming up in .NET 2.0 the ListView control now supports virtual mode, which is used to cut down on the amount of memory used by the ListView but requires more work from the developer. It does this by raising several events when it needs some information about the items to be displayed. This post isn’t going to focus on that, but rather one aspect that may be missed when you go to use this new functionality.”

    Is there a blog about this…..I’m getting lost on how to populate a listview in virtual mode.

    Thanks,
    Trey

    Posted by Trey | August 17, 2005, 10:36 am
  2. hi,
    i m a novice to .net and desperately wanna to populate a list in virtualmode… i cant find any stuff in http://www…could u blog that…

    Posted by rajesh | December 7, 2005, 6:09 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archive

%d bloggers like this: