Click here to Skip to main content
15,884,859 members
Articles / Desktop Programming / Windows Forms

ListView in VirtualMode and checkboxes

Rate me:
Please Sign up or sign in to vote.
4.13/5 (10 votes)
23 Mar 2007CPOL2 min read 118.7K   3.1K   44   17
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.

C#
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.

C#
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.

C#
...
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:

C#
...
    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.

C#
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.

C#
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.

C#
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:

C#
...
    // 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.

C#
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)


Written By
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

 
QuestionHow to iterate through checked items? Pin
Member 1590599715-Mar-23 8:19
Member 1590599715-Mar-23 8:19 
GeneralIn Details view, nothing is showing in the listctrl Pin
loyal ginger4-Apr-11 10:23
loyal ginger4-Apr-11 10:23 
GeneralRe: In Details view, nothing is showing in the listctrl Pin
Alphons van der Heijden5-Apr-11 0:40
professionalAlphons van der Heijden5-Apr-11 0:40 
GeneralAfter shuffling items selecting one item shows two items !!! Pin
samprog6-Jun-10 19:34
samprog6-Jun-10 19:34 
GeneralCheckbox problem [modified] Pin
C Is Sharp21-Dec-08 19:15
C Is Sharp21-Dec-08 19:15 
GeneralRe: Checkbox problem Pin
Alphons van der Heijden22-Dec-08 2:13
professionalAlphons van der Heijden22-Dec-08 2:13 
GeneralRe: Checkbox problem Pin
C Is Sharp22-Dec-08 19:53
C Is Sharp22-Dec-08 19:53 
GeneralRe: Checkbox problem Pin
Alphons van der Heijden23-Dec-08 0:06
professionalAlphons van der Heijden23-Dec-08 0:06 
GeneralRe: Checkbox problem Pin
C Is Sharp23-Dec-08 17:22
C Is Sharp23-Dec-08 17:22 
Hey budy my also listview. Blush | :O
GeneralAbout item fill Pin
C Is Sharp15-Dec-08 22:46
C Is Sharp15-Dec-08 22:46 
GeneralRe: About item fill Pin
Alphons van der Heijden16-Dec-08 4:56
professionalAlphons van der Heijden16-Dec-08 4:56 
QuestionDraw header of columns in detail mode Pin
jasanguineti26-Jul-07 8:35
jasanguineti26-Jul-07 8:35 
AnswerRe: Draw header of columns in detail mode Pin
Alphons van der Heijden27-Jul-07 23:31
professionalAlphons van der Heijden27-Jul-07 23:31 
GeneralRe: Draw header of columns in detail mode Pin
c-fliege12-Sep-07 4:09
c-fliege12-Sep-07 4:09 
QuestionImages in Details mode Pin
The Marksman27-Mar-07 23:12
The Marksman27-Mar-07 23:12 
AnswerRe: Images in Details mode Pin
The Marksman28-Mar-07 3:42
The Marksman28-Mar-07 3:42 
GeneralRe: Images in Details mode Pin
Alphons van der Heijden28-Mar-07 14:02
professionalAlphons van der Heijden28-Mar-07 14:02 

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

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