Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Flicker-free ListView in .NET and XP

0.00/5 (No votes)
26 Jan 2003 1  
This article discusses the problems with the .NET ListView and offers a solution to fix those problems.

Sample Image - ListViewXP.gif

Introduction

The focus of this article is to extend and improve the .NET ListView control. The current ListView control is very useful, but has a nasty flicker problem associated with it. My goal is to eliminate or significantly reduce this flicker. The solution provided in this article only works with Windows XP with an associated manifest file. This is the first of three articles I am writing to improve the ListView control. The others will not require XP. In addition, other things I will discuss in this article do not require XP.

It flickers

There are two situations in which you will encounter flickering.

  • Dynamically adding items

    If you attempt to add multiple items while using an ImageList with multiple icons (in a for or foreach loop), and you would like these items to display as they are being added, you need to use Refresh() or Update() (you can use others like Application.DoEvents()). Any of the above mentioned will cause an annoying flicker. To avoid the flicker, you do not place Refresh(), Update() etc inside the for loop. This will cause the ListView to be blank until all of the items are added. At times, this is the best way to go, but if doing this requires a significant amount of time, it is not a good idea as the user will think the program has locked up.

  • Resizing the main form with a ListView docked

    When a ListView is Docked, as in Windows Explorer (and you have a good amount of items), resizing the main form will cause all of the items to flicker.

Update: I originally had three. Third one being updating/changing an item, but you just need to use Update() rather than Refresh() to fix this.

Why does it flicker?

When you add a new item to the ListView, the control invalidates itself. This causes the background to be erased, and all items to be redrawn again. It should only invalidate the bounds of the new item, causing only the item to be drawn, but it doesn't. This means that calling Refresh() and Update() will have the same effect, where you would expect Update() to only update the new or changed items. In my next article, I will discuss a couple of techniques to allow only the newly added item to be redrawn.

Another reason it flickers is because it is not truly double-buffered. You can extend the ListView class, and add SetStyle(ControlStyles.DoubleBuffer, true), but it has no effect. The technique described here shows you how to double buffer the ListView.

DoubleBuffering the ListView

If you are familiar with programming the ListView (or CListCtrl) using only the Win32 API, or MFC, you will notice that you can set particular styles for the ListView. Most of these styles are already set in the .NET ListView, and are customizable (for example, the ViewModes, how icons will be aligned.. will they be auto-arranged, etc).

There are also "Extended" Styles for the ListView. These styles add a few extras such as using One-Click activate with hot-tracking (similar to Windows 98 Explorer in web-mode, where clicking the item once will launch the item, "entering" the item will cause it to be selected" etc..) There is also an extended style to allow gridlines to be drawn around items in Details/Report mode (This is already implemented in .NET, when you choose details view and show gridlines).

In Windows XP, there is an extended-style called LVS_EX_DOUBLEBUFFER. This is what we want. Unfortunately it is only available for Common Controls version 6, which means we need Windows XP as well as a manifest file (or embedded resource). Additionally there is a style called LVS_EX_BORDERSELECT which tells the ListView (in Large Icon mode) to highlight the border of the icon rather than to paint over it (This is available with Common Controls version 4.71, so this will work without XP).

So now our goal is to actually make use of these extended styles. This is pretty easy to do if you're familiar with the SendMessage Windows function. We import this function from user32.dll, and use it to retrieve and set extended styles. Here's the code:

public void SetExStyles()
{
    LVS_EX styles = (LVS_EX)SendMessage(this.Handle, 
        (int) LVM.LVM_GETEXTENDEDLISTVIEWSTYLE, 0,0);
    styles |= LVS_EX.LVS_EX_DOUBLEBUFFER | LVS_EX.LVS_EX_BORDERSELECT;
    SendMessage(this.Handle, 
        (int) LVM.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, (int) styles);
}

We start by retrieving any existing Extended Styles. We then add DOUBLEBUFFER and BORDERSELECT, and use SendMessage to add these extra styles to the current ListView. This method should be called AFTER the ListView's handle has been created. If not, it will not work as the Handle has not been defined yet. In other words, do not make a call to this in your main Form's constructor.. it should happen after the entire form has loaded.

NOTE: LVS_EX is an enumerated type of int. Each constant in here defines the proper ExtendedStyle. LVM is also an enumerated type representing ListView messages.

Once you've made a call to this method, you can make a loop similar to this to add items to this ListView:

for (int i=0; i < 500; i++)
{
   listviewXp.Items.Add("item name", iconIndex);
   listviewXp.Update();
}

Now you will be able to see the items as they are being drawn, and you will no longer get the nasty flicker. In addition, if your ListView is docked, you can resize your form without the flicker problem. You can also call listview.Refresh() or listview.Update() after you have made a change to an existing item and the change will be made without flicker.

Running and using the sample

  • Using the sample demo

    Be sure you are using Windows XP and have both the exe and manifest file in the same directory. Run it, and press the button to watch the items appear without flicker. If you are not using XP, you will still see flicker, but you will be able to see the BorderSelect mode.

  • Compiling the sample app

    Open up Visual Studio .NET and compile it. Before you run it, copy the manifest file to the Debug or Release directory where the exe is.

  • Using ListViewXP in your own app

    Just copy the ListViewXP.cs file and add it to your app. Note that if you want the double buffering effect, you must provide the manifest file. You can copy the one I provided and rename it to YourAppName.exe.manifest. You may use and distribute this class freely, but if you do so, please include a comment that includes my name and a link to this article. Also, if you do use it, please let me know how it worked for you.

Conclusion

Using the SendMessage function from user32.dll allows us to extend the .NET ListView, so we can add DoubleBuffering support in XP to eliminate flicker. Additionally, we can use this function to add other extended ListView styles, and this technique can be applied to other controls as well. Hope you enjoyed the article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here