I had a regular Forms.ListView and converted it to Virtual list. Implemented the RetrieveVirtualItem
and everything was working fine.
Then I decided that I'll add cache and eventually I'll need sorting and who knows what else. Since I've inherited the code and it was already somewhat messy, I decided to yank my changes and move them to a separate class, namely: derive from ListView, e.g. class MyOwnListView : ListView
so I've moved it and also added CacheVirtualItems.
After implementing both of these methods, I replaced:
private System.Windows.Forms.ListView someListView;
with
private MyOwnListView someListView;
on the main form.
So far so good..it runs, doesn't crash, however (and I only have about 60 items for now..) when I move the scroll bar, a lot of them don't repaint, so you'll see empty white rows, and sometimes it will repaint/show after clicking on that row. I also get partially displayed and drawn row, such as the top of the row won't be displaying in its entirety.
I'm not sure what the problem is, I tried adding DoubleBuffered=true;
I also added to my constructor the following: (per some suggestion I've found somewhere here and/or googling..)
SetStyle( ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true );
SetStyle( ControlStyles.EnableNotifyMessage, true );
and this method:
protected override void OnNotifyMessage( Message m )
{
//Filter out the WM_ERASEBKGND message
if ( m.Msg != 0x14 )
{
base.OnNotifyMessage( m );
}
}
My code overall is very similar to this:..just to give you an idea:
public class MyListView: ListView
{
private ListViewItem[] cache;
private int firstItem;
public MyListView()
{
SetStyle( ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true );
SetStyle( ControlStyles.EnableNotifyMessage, true );
RetrieveVirtualItem += new RetrieveVirtualItemEventHandler( xxx_RetrieveVirtualItem );
CacheVirtualItems += new CacheVirtualItemsEventHandler( xxx_CacheVirtualItems );
}
private void xxx_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
if (cache != null && e.ItemIndex >= firstItem && e.ItemIndex < firstItem + cache.Length)
e.Item = cache[e.ItemIndex - firstItem];
else
e.Item = GetItem(e.ItemIndex);
}
private void xxx_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
{
if (cache != null && e.StartIndex >= firstItem && e.EndIndex <= firstItem + cache.Length)
return;
firstItem = e.StartIndex;
int length = e.EndIndex - e.StartIndex + 1;
cache = new ListViewItem[length];
for (int i = 0; i < cache.Length; i++)
cache[i] = GetItem(firstItem + i);
}
Now, GetItem, basically accesses a List<someobject>, gets the object out of list, and based on that
it creates new ListViewItem and returns it.
}
EDIT: I've added some debugging code to the xxx_CacheVirtualItems. And it appears that everytime I scroll it comes back that the item was not found and is adding it again to the cache. Not sure why yet. I would expect that after the first scroll all the way down it would keep them inside the cache. I'm still looking.
I also tried adding:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
and tried //Application.SetCompatibleTextRenderingDefault(true);
That application didn't have these at all..these two lines did something interesting. SetCompatibleTextRenderingDefault with false, did not scroll at all, while SetCompatibleTextRenderingDefault with true did scroll, but only down and once I've reach the bottom it stopped. but the screen didn't have any painting/refresh problems..