Example:
- listview with 20000 virtual items
- RetrieveVirtualItem() feeds some dynamically created items
- scroll to the end of the list
- set VirtualListSize to 200 (via a button click for instance)
You'll then crash internally with an ArgumentOutOfRangeException exception (here at index 200). Nothing helps to avoid this. Really odd. The crash happens somewhere in ListViewItemCollection.get_Item(). Looks like something isn't aware that things are virtualized...
Am I doing something wrong
Or is this another listview bug
The VB.NET source of the test app can be downloaded here:
http://www.hotpixel.net/tmp/VirtLstViewBug.zip
Thanks for reading!

Virtual ListView crashes on VirtualListSize
mcgyver74
Thanks alot guys great stuff.
SamGB
If Value < 0
Error
If (NewValue != CurrentValue)
If In Details Mode And Created And ...
Get the index of the first item displayed in the control (not necessarily the first item in the list)
Set the new virtual list size and send a message to notify the underlying control
If we have the index of the first item
Find the new top item in the list
Set TopItem to the new top item in the list
End If
End If
The problem lies in determining the new top item. It does Math.Min(num1, VirtualListSize). This basically says that if the current top item is less than the new list size then just keep it otherwise set the top item index to be the new list size. Here is where the exception will occur. If the top item is set to the list size then we'll be off by one (because in a list of size 200 the last indexable value is 199).
As a result if the top item in the list (the first displayed item) is less than the virtual list size then the code will work otherwise it'll crash. The workaround would be to modify your code to set the TopItem before you set the new virtual list size. This would resolve your crash until the issue is fixed. Hopefully MS trowls this forum for bug submissions otherwise you'll need to notify them directly.
Good find,
Michael Taylor - 11/28/05
wojtek.n
I don't believe this is a glitch.
When you have the listview set with a large number of items and scroll down, the currently loaded index is still stored even when you change the virtuallistsize property. As a result, the index is out of bounds with the newly reset dimensions and an error is thrown. To get around this simply add:
ListView1.EnsureVisible(0)
before you change the size. This makes sure that the currently selected index is lower than the size of the list and will not create the out of bounds error.
tgm_0402
Breezy-WA
Here is a corrected class that provides the intended behavior of System.Windows.Forms.ListView without the bug:
using
System;using
System.Windows.Forms;using
System.ComponentModel;/// <summary>
/// Creates a ListView that fixes for the <see cref="VirtualListSize"/>VirtualListSize bug. /// </summary>public class VirtualListView : ListView
{
base.VirtualListSize = value;
}
}
}
ges
However your solution does seem to be more elegant than the SEH suggestion or even setting the TopItem explicitly. The only thing I don't like about your suggestion is the fact that every time the tree changes the user will be thrown to the top of the tree again. My users really don't like this so I have to go through hoops when changing a tree such that the user doesn't see the tree jump (unless necessary). Explorer itself is a good example. If you expand a deeply nested directory and then delete the root Explorer will simply delete the node and leave the tree where it is. This makes it easier and more visually appealing to users. That is why I would write the code using TopItem. Then the tree changes only if necessary.
Thanks!
Michael Taylor - 12/5/05
G.Lakshmi
try { // HACK: Catch exceptions sometimes thrown by ListView bug
listView.VirtualListSize = virtualList.Count;
} catch (ArgumentOutOfRangeException) {
Debug.WriteLine("(VirtualListViewClient caught VirtualListSize exception)");
} catch (NullReferenceException) {
Debug.WriteLine("(VirtualListViewClient caught VirtualListSize exception)");
}
Notice how I also got a NullReferenceException on occasion, which might be a related bug It appears less frequently than the ArgumentOutOfRangeException, but it also keeps occurring...
Amy Hagstrom
Bob-12
topIndex = Math.Min(topIndex, value - 1);
will evaluate to 0 (zero). Which is fine (and correct), but unfortunately the next line checks to see if the 'topIndex' variable is greater than 0 before setting the TopItem property. Since it is not greater than zero, the TopItem property remains unchanged and is probably equal to 150 or something (depending on the size of your form). At this point, you end up getting the same exception when you try to set the VirtualListSize property to 1.
So what you could do is change:
topIndex = Math.Min(topIndex, value - 1);
to
// Compute the top index, making sure not to go negative
// if a value of 0 (zero) is passed in.
topIndex = Math.Min(topIndex, Math.Abs(value - 1));
Then get rid of the if statement:
if (topIndex > 0)
and just always set the TopItem property.
This should handle all cases without any errors.