2 out of 3 rated this helpful - Rate this topic

ListView.VirtualMode Property

Gets or sets a value indicating whether you have provided your own data-management operations for the ListView control.

Namespace:  System.Windows.Forms
Assembly:  System.Windows.Forms (in System.Windows.Forms.dll)
public bool VirtualMode { get; set; }

Property Value

Type: System.Boolean
true if ListView uses data-management operations that you provide; otherwise, false. The default is false.
Exception Condition
InvalidOperationException

VirtualMode is set to true and one of the following conditions exist:

Setting the VirtualMode property to true puts the ListView into virtual mode. In Virtual mode, the normal Items collection is unused. Instead, ListViewItem objects are created dynamically as the ListView requires them.

Virtual mode can be useful under many circumstances. If a ListView object must be populated from a very large collection already in memory, creating a ListViewItem object for each entry can be wasteful. In virtual mode, only the items required are created. In other cases, the values of the ListViewItem objects may need to be recalculated frequently, and doing this for the whole collection would produce unacceptable performance. In virtual mode, only the required items are calculated.

In order to use virtual mode, you must handle the RetrieveVirtualItem event, which is raised every time the ListView requires an item. This event handler should create the ListViewItem object that belongs at the specified index. In addition, the VirtualListSize property must be set to the size of the virtual list.

Handling the SearchForVirtualItem event enables searching in virtual mode. If this event is not handled, the FindItemWithText and FindNearestItem methods will return null.

You can handle the CacheVirtualItems event in order to maintain a cache of ListViewItem objects. If the calculation or lookup to create a ListViewItem object is expensive, maintaining a cache can improve performance.

If the View property is set to Tile, the value will automatically be changed to LargeIcon when VirtualMode is set to true.

In virtual mode, the Items collection is disabled. Attempting to access it results in an InvalidOperationException. The same is true of the CheckedItems collection and the SelectedItems collection. If you want to retrieve the selected or checked items, use the SelectedIndices and CheckedIndices collections instead.

This example illustrates a simple ListView whose contents are the first ten thousand squares. It handles searching and uses a cache for increased performance.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;

public class Form1 : Form
{
    private ListViewItem[] myCache; //array to cache items for the virtual list
    private int firstItem; //stores the index of the first item in the cache

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public Form1()
    {
        //Create a simple ListView.
        ListView listView1 = new ListView();
        listView1.View = View.SmallIcon;
        listView1.VirtualMode = true;
        listView1.VirtualListSize = 10000;

        //Hook up handlers for VirtualMode events.
        listView1.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(listView1_RetrieveVirtualItem);
        listView1.CacheVirtualItems += new CacheVirtualItemsEventHandler(listView1_CacheVirtualItems);
        listView1.SearchForVirtualItem += new SearchForVirtualItemEventHandler(listView1_SearchForVirtualItem);

        //Add ListView to the form.
        this.Controls.Add(listView1);

        //Search for a particular virtual item.
        //Notice that we never manually populate the collection!
        //If you leave out the SearchForVirtualItem handler, this will return null.
        ListViewItem lvi = listView1.FindItemWithText("111111");

        //Select the item found and scroll it into view.
        if (lvi != null)
        {
            listView1.SelectedIndices.Add(lvi.Index);
            listView1.EnsureVisible(lvi.Index);
        }
    }

    //The basic VirtualMode function.  Dynamically returns a ListViewItem
    //with the required properties; in this case, the square of the index.
    void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
    {
        //Caching is not required but improves performance on large sets.
        //To leave out caching, don't connect the CacheVirtualItems event 
        //and make sure myCache is null.

        //check to see if the requested item is currently in the cache
        if (myCache != null && e.ItemIndex >= firstItem && e.ItemIndex < firstItem + myCache.Length)
        {
            //A cache hit, so get the ListViewItem from the cache instead of making a new one.
            e.Item = myCache[e.ItemIndex - firstItem];
        }
        else
        {
            //A cache miss, so create a new ListViewItem and pass it back.
            int x = e.ItemIndex * e.ItemIndex;
            e.Item = new ListViewItem(x.ToString());
        }
    }

    //Manages the cache.  ListView calls this when it might need a 
    //cache refresh.
    void listView1_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
    {
        //We've gotten a request to refresh the cache.
        //First check if it's really neccesary.
        if (myCache != null && e.StartIndex >= firstItem && e.EndIndex <= firstItem + myCache.Length)
        {
            //If the newly requested cache is a subset of the old cache, 
            //no need to rebuild everything, so do nothing.
            return;
        }

        //Now we need to rebuild the cache.
        firstItem = e.StartIndex;
        int length = e.EndIndex - e.StartIndex + 1; //indexes are inclusive
        myCache = new ListViewItem[length];

        //Fill the cache with the appropriate ListViewItems.
        int x = 0;
        for (int i = 0; i < length; i++)
        {
            x = (i + firstItem) * (i + firstItem);
            myCache[i] = new ListViewItem(x.ToString());
        }

    }

    //This event handler enables search functionality, and is called
    //for every search request when in Virtual mode.
    void listView1_SearchForVirtualItem(object sender, SearchForVirtualItemEventArgs e)
    {
        //We've gotten a search request.
        //In this example, finding the item is easy since it's
        //just the square of its index.  We'll take the square root
        //and round.
        double x = 0;
        if (Double.TryParse(e.Text, out x)) //check if this is a valid search
        {
            x = Math.Sqrt(x);
            x = Math.Round(x);
            e.Index = (int)x;

        }
        //If e.Index is not set, the search returns null.
        //Note that this only handles simple searches over the entire
        //list, ignoring any other settings.  Handling Direction, StartIndex,
        //and the other properties of SearchForVirtualItemEventArgs is up
        //to this handler.
    }
}


.NET Framework

Supported in: 4, 3.5, 3.0, 2.0

.NET Framework Client Profile

Supported in: 4, 3.5 SP1

Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows XP SP2 x64 Edition, Windows Server 2008 (Server Core not supported), Windows Server 2008 R2 (Server Core supported with SP1 or later), Windows Server 2003 SP2

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.
Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Spurious item requests and importance of caching
Additional example is useful, thankyou. Just to highlight an important point (which is covered in the Microsoft example), the RetrieveVirtualItem may be asked for non-cached items. For example, if the list view is currently showing items 100,000 - 100,020 and the user scrolls to 120,000-120,020, RetrieveVirtualItem will get spurious calls for other list view items (item 0 for example!). $0$0 $0 $0Whilst you can get away without caching, its useful to note that in populating the list view the control may make 4 requests for the same item, and if the user moves the mouse over an item you can get 30 or more requests for the same item, so it pays to cache!$0
Excellent sample!
Thank you very much for this sample!
Virtual Sense
Guys, in the whole of MSDN the example given in the VirtualMode section must be the worst choice for sample code. Because the data is created in the calls rather than linked to user data (as it would be 100% of the time), this sample doesn't help anyone until after you have been to other sites learnt how Virtual listboxes work, then come back and now your example makes sense.

So for the sake of others that struggled I have a more meaningful example. It is not a complete example because I have not yet got a working cache, the start and end index keep going out of range, even if I check that they are in range before I use them, so something missing there.

But still even without a cache VirtualMode is amazingly fast.

Anyway start with some user data -

private List<String> myList = new List<string>();
,

        private void Form1_Load(object sender, EventArgs e)
        {
            //set up myList
            for (int i = 0; i < 200; i++)
            {
                myList.Add(string.Concat("A", (i + 1).ToString()));
            }
            listView1.VirtualListSize = myList.Count();
        }

Remember that we do not directly add items to out listview, instead we wait for RetrieveVirtualItem so ask us for the data.

        private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {
                ListViewItem lvi = new ListViewItem(myList[e.ItemIndex]);
                e.Item = lvi;
        }

This is enough to fill our listview and scroll items. remember that you are only asked for the data that is needed for the view, so it is a fast way of updateing a ListView.

What about adding data to our Listview, we know we must add the items to our own myList, so how do we tell the ListView what we have done? Well that turns out to be very easy.

        private void btnAddItem_Click(object sender, EventArgs e)
        {
           //Add our item to our list
            myList.Add("Hello Mate");
          //Tell ListView that the number of items has changed
            listView1.VirtualListSize = myList.Count();
        }

Last searches. The only thing to remember here is that though the Listbox will initiate the search, we actually do the searching and we are responsible for telling the ListView to scrol to the result.

First to innitiate the search

        private void btnFindItem_Click(object sender, EventArgs e)
        {
            //Search for a particular item.

            ListViewItem lvi = listView1.FindItemWithText("Hello Mate");

            //Select the item found and scroll it into view.
            if (lvi != null)
            {
                listView1.SelectedIndices.Add(lvi.Index);
                listView1.EnsureVisible(lvi.Index);
            }

        }

Now the actual search

        private void listView1_SearchForVirtualItem(object sender, SearchForVirtualItemEventArgs e)
        {
            //find the item given as text in your own list, then set the index of this item
            //in e.index
            int x = myList.IndexOf(e.Text);
            e.Index = x;
           
        }
We did not actually need to search through the ListView, we can just find the item in our list and scroll directly with EnsureVisible().  This is a particularly nice thing because in a lot of data I found it very handy to have indexes to certain parts preset, so I can do something like -

listView1.EnsureVisible( myIndex.WMVGroup )