Click here to Skip to main content
Click here to Skip to main content

ListView in VirtualMode and checkboxes

, 23 Mar 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
A listview control in VirtualMode is the fastest way when working with a lot of items. Special care, however, should be given for items containing checkboxes.

Screenshot - ListViewVirtualMode1.gif

Introduction

Loading a ListView control with a lot of items is a very slow process. As of .NET 2.0, the ListView control contains a VirtualMode. With a little extra code, it can speed up the process significantly. However, special care should be taken when using check boxed items.

Background

There are two things to do to make the ListView work in VirtualMode. Set some properties on the ListView control, and make an event handler to 'retrieve' a virtual item.

void listView_RetrieveVirtualItem(object sender,
     RetrieveVirtualItemEventArgs e)
{
        // e contains ItemIndex
        e.Item = listViewItem;
}
....
void SetupListview(bool blnVirtual)
{
    ...
    this.listView1.VirtualMode = true;
    this.listView1.RetrieveVirtualItem +=
         new RetrieveVirtualItemEventHandler(listView_RetrieveVirtualItem);
    ...
}

Using the attached source code

The code shows a test framework where you can switch between Normal and VirtualMode. It measures the time it takes to load 100000 (one hundred thousand) ListViewItems.

It uses a static cache for the ListViewItems to make things simple.

private ListViewItem[] lvi;
...
private void Test()
{
    // You can switch between Virtual and Normal
    bool blnVirtual = true;

    // Get the ListViewItem cache up and running
    int NR = 100000;

    lvi = new ListViewItem[NR];
    for (int intI = 0; intI < lvi.Length; intI++)
        lvi[intI] = new ListViewItem(intI + " test");

    // Check some random items, just for testing
    lvi[3].Checked = true;
    lvi[5].Checked = true;
    lvi[12].Checked = true;
    lvi[NR-2].Checked = true;
...
}

.NET 2.0 has a nice Stopwatch, and I used it to measure the performance of loading the items from our cache into the ListView control.

...
Stopwatch stopwatch = new Stopwatch();
stopwatch.Reset();
stopwatch.Start();

SetupListview(blnVirtual);

stopwatch.Stop();
this.Text = "ListView VirtualMode=" + blnVirtual + 
        " : "+ lvi.Length + " items in " + 
        stopwatch.ElapsedMilliseconds + " mS";
...

To test the normal performance of the ListView control, the following code is used:

...
    this.listView1 = new ListView();
    this.listView1.Dock = DockStyle.Fill;

    this.listView1.View = View.List;
    this.listView1.CheckBoxes = true;

    this.listView1.Items.AddRange(lvi);
...

As a result, loading of 100000 cached items in Normal mode took somewhat close to 35 seconds.

ListViewVirtualMode2.gif - ListView in NormalMode

The picture in the head of this article shows the time for the same test, which is 15mS. VirtualMode is more than 2000 times faster compared to the normal use of the control.

Points of interest

There are some problems when using checkboxes and VirtualMode. When loading items, only the items which are checked have a visible checkbox. The others don't. Also, a click on a checkbox itself results in nothing. A double-click on an item shows a checked item, only when the item loses focus. These are the things that I found, maybe there are more known problems features.

To make a workaround, I had to set the ListView control for OwnerDrawing, and hooked a click and double-click handler on to the control.

Because there is nothing wrong with the normal ListView, for drawing text of the items, the DrawDefault property is set. For getting the checkbox to show for non-checked items as well, the property e.Item.Checked switches between true and false to get the job done.

void listView_DrawItem(object sender, DrawListViewItemEventArgs e)
{
    e.DrawDefault = true;
    if (!e.Item.Checked)
    {
        e.Item.Checked = true;
        e.Item.Checked = false;
    }
}

To handle the single-click on the checkbox, first get the ListViewItem from the position of the mouse-click by using GetItemAt. When a valid item is found, check the position of the mouse against the item to find out if the checkbox was hit. Last of all, do a redrawing of the item by using Invalidate.

void listView_MouseClick(object sender, MouseEventArgs e)
{
    ListView lv = (ListView)sender;
    ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
    if (lvi != null)
    {
        if (e.X < (lvi.Bounds.Left + 16))
        {
            lvi.Checked = !lvi.Checked;
            lv.Invalidate(lvi.Bounds);
        }
    }
}

Because double-clicking an item works, only the drawing is handicapped, and we have to do the drawing ourselves.

void listView_MouseDoubleClick(object sender, MouseEventArgs e)
{
    ListView lv = (ListView)sender;
    ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
    if(lvi!=null)
        lv.Invalidate(lvi.Bounds);
}

Prepare the ListView control to use the event handlers:

...
    // This makes it real fast!!
    this.listView1.RetrieveVirtualItem +=
        new RetrieveVirtualItemEventHandler(
        listView_RetrieveVirtualItem);
    this.listView1.VirtualListSize = lvi.Length;
    this.listView1.VirtualMode = true;

    // This is what you need, for drawing unchecked checkboxes
    this.listView1.OwnerDraw = true;
    this.listView1.DrawItem +=
        new DrawListViewItemEventHandler(listView_DrawItem);

    // Redraw when checked or doubleclicked
    this.listView1.MouseClick +=
        new MouseEventHandler(listView_MouseClick);
    this.listView1.MouseDoubleClick +=
        new MouseEventHandler(listView_MouseDoubleClick);
...

Bind this all together to have a ListView working in both modes.

void SetupListview(bool blnVirtual)
{
    // Get ListView working
    this.listView1 = new ListView();
    this.listView1.Dock = DockStyle.Fill;

    // This is what we want!!
    this.listView1.View = View.List;
    this.listView1.CheckBoxes = true;

    if (blnVirtual)
    {
        // This makes it real fast!!
        this.listView1.RetrieveVirtualItem +=
            new RetrieveVirtualItemEventHandler(
            listView_RetrieveVirtualItem);
        this.listView1.VirtualListSize = lvi.Length;
        this.listView1.VirtualMode = true;

        // This is what you need, for drawing unchecked checkboxes
        this.listView1.OwnerDraw = true;
        this.listView1.DrawItem +=
            new DrawListViewItemEventHandler(listView_DrawItem);

        // Redraw when checked or doubleclicked
        this.listView1.MouseClick += 
            new MouseEventHandler(listView_MouseClick);
        this.listView1.MouseDoubleClick +=
            new MouseEventHandler(listView_MouseDoubleClick);
    }
    else
    {
        // The other way
        this.listView1.Items.AddRange(lvi);
    }

    // Show in main form
    this.Controls.Add(this.listView1);
}

History

As of this writing, it is version 1.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Alphons van der Heijden
Retired Van der Heijden Holding BV
Netherlands Netherlands
I'm Alphons van der Heijden, living in Lelystad, Netherlands, Europa, Earth. And currently I'm retiring from hard working ( ;- ), owning my own company. Because I'm full of energy, and a little to young to relax ...., I don't sit down, but create and recreate software solutions, that I like. Reinventing the wheel is my second nature. My interest is in the area of Internet technologies, .NET etc. I was there in 1992 when Mosaic came out, and from that point, my life changed dramatically, and so did the world, in fact. (Y)

Comments and Discussions

 
GeneralIn Details view, nothing is showing in the listctrl Pinmemberloyal ginger4-Apr-11 11:23 
GeneralRe: In Details view, nothing is showing in the listctrl PinmemberAlphons van der Heijden5-Apr-11 1:40 
GeneralAfter shuffling items selecting one item shows two items !!! Pinmembersamprog6-Jun-10 20:34 
GeneralCheckbox problem [modified] PinmemberMember 205815421-Dec-08 20:15 
GeneralRe: Checkbox problem Pinmemberalphons22-Dec-08 3:13 
GeneralRe: Checkbox problem PinmemberMember 205815422-Dec-08 20:53 
GeneralRe: Checkbox problem Pinmemberalphons23-Dec-08 1:06 
GeneralRe: Checkbox problem PinmemberMember 205815423-Dec-08 18:22 
GeneralAbout item fill PinmemberMember 205815415-Dec-08 23:46 
GeneralRe: About item fill Pinmemberalphons16-Dec-08 5:56 
QuestionDraw header of columns in detail mode Pinmemberjasanguineti26-Jul-07 9:35 
AnswerRe: Draw header of columns in detail mode Pinmemberalphons28-Jul-07 0:31 
GeneralRe: Draw header of columns in detail mode Pinmemberc-fliege12-Sep-07 5:09 
QuestionImages in Details mode PinmemberThe Marksman28-Mar-07 0:12 
AnswerRe: Images in Details mode PinmemberThe Marksman28-Mar-07 4:42 
GeneralRe: Images in Details mode Pinmemberalphons28-Mar-07 15:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141216.1 | Last Updated 23 Mar 2007
Article Copyright 2007 by Alphons van der Heijden
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid