Click here to Skip to main content
11,926,961 members (50,202 online)
Click here to Skip to main content
Add your own
alternative version


56 bookmarked

Flicker-free ListView in .NET - Part 2

, 3 Feb 2003
Rate this:
Please Sign up or sign in to vote.
This article discusses a couple of ways to reduce flicker in the .NET Listview.


This is another article about reducing flicker in the ListView. The original article I wrote only works in Windows XP (with manifest file to use Common Controls version 6). You can view it by clicking on this link ListViewXP

This article will focus on two other techniques. Neither of which require Windows XP. Please note that the focus of this article is to dynamically add multiple items with a well-sized image-list without flicker.

WndProc Technique

The first technique involves catching and manipulating messages. As I mentioned in my previous article, every time you add an item to the ListView, the entire control becomes invalidated. When adding multiple items in a loop, the control only paints when the loop ends unless you add Update() or Refresh() (or other various methods) to the end of the loop. Using Update(), Refresh() etc, will cause flickering because the control is constantly invalidated and repainting itself. One way to observe this is to override the WndProc method, and store all messages inside an ArrayList, or another structure. Then when you view the ArrayList, you will see the numbers corresponding to WM_ERASEBKGND and WM_PAINT. We can use this knowledge to help us.

Part of our design of this new class is to allow the programmer to specify that he/she is adding a new item. We create a new method called UpdateItem(int iIndex). The programmer can call this, and it will draw the newly created item only.

public void UpdateItem(int iIndex)
    updating = true;
    itemnumber = iIndex;
    updating = false;

First we have a bool private member variable called updating. This will be used in the WndProc method below. When it is set to true, the WndProc method will catch messages. When false, WndProc does nothing except to callbase.WndProc() . itemnumber is another newly added private member. It holds the index of the newly added item. Update() is used to redraw invalidated regions of the control (which we play with in WndProc), and finally it sets updating to be false so that messages are no longer being caught by our code. Now we override WndProc in order to make our adjustments.

protected override void WndProc(ref Message messg)
    if (updating)  
        // We do not want to erase the background, 
        // turn this message into a null-message
        if ((int)WM.WM_ERASEBKGND == messg.Msg)
            messg.Msg = (int) WM.WM_NULL;
        else if ((int)WM.WM_PAINT == messg.Msg)
            RECT vrect = this.GetWindowRECT();
            // validate the entire window                
            ValidateRect(this.Handle, ref vrect);

            //Invalidate only the new item
    base.WndProc(ref messg);

As you can see, we capture the WM_ERASEBKGND message, and we convert it to a NULL message. This will stop the ListView from being erased. WM_PAINT is used to redraw an invalidated area. Since the entire control is invalidated, we need to do a little work. First we Validate the entire viewable area. Doing this will cause WM_PAINT to do nothing, so we follow up by invalidating only the bounds of the new item. Now when painting occurs, it will only occur for the new item because the rest of the control has been validated.

WM_ERASEBKGND, and WM_PAINT are enum'd types representing the int values of the Window messages. You can view these in the code. ValidateRect is a Win32 function that allows us to validate a certain region. Since there is no equivalent in .NET, we import this from user32.dll (see code). RECT is a structure similar to Rectangle, but is needed for the ValidateRect function. When we call ValidateRect, it validates the entire window area of the ListView. We then follow by using the control's Invalidate method to invalidate the bounds of the new item. Now only the new item's bounds are invalidated. This means that only the new item will be painted. Since we captured WM_ERASEBKGND and validated the rest of the control, each item will be drawn as it is added (provided that you use the newly added UpdateItem(index) function). If you don't use UpdateItem(), WndProc will do nothing because "updating" variable will always be false.

NOTE - I'd like to give credit to Carlos H Perez. He does something similar in his ListViewEx control, and part of this idea is based on that work.

Now we can do this (in our main application)

for (int i=0; i < 500; i++)
   ListViewItem lvi = 
      new ListViewItem("Item #" + i.ToString(),  indexOfImage);

Now the items will be painted as they are added to the list view without flicker.

Pure .NET Technique

This next technique is pure .NET and you do not need to extend the ListView class. This technique does not draw the items as they are being added, but describes an alternative way to stop the user from waiting for a long time.

If we do not associate an ImageIndex with a listView item (use -1 as ImageIndex), we can add items to the ListView pretty quickly:

for (int i=0; i < 500; i++)
   ListViewItem lvi = 
      new ListViewItem("Item #" + i.ToString(), -1);

Since we are not calling Update() or Refresh(), we will not see the items as they are being added, but this will be done pretty fast since no images are associated with the ListView.

Now all of the items will be added, so we need to associate an Image with them.

for (int i=0; i < 500; i++)
     ListViewItem lvi = this.listView.Items[i] ; 
        // get the already existing item

     lvi.ImageIndex = someNumber ; 
        // Now we associate the item with an image in the imagelist;

        // Invalidate the already-existing item
        // Will force the invalidated region to be redrawn

Before this loop begins, all items will be there without an image. Now we simply associate the image, and invalidate the region of the item. CallingUpdate() will only redraw the invalidated region. In this case, only the bounds of the item will be invalidated, so the image will be drawn to the screen without affecting the other ListView items.

This is good for a thumbnail program. You can add the names of the thumbnails in the first loop, and in the second loop, you can load the bitmaps into the imagelist, associate the already created item with the image index of the newly added image, and now each image will be painted as it's being loaded. What makes it even better is that you can throw this second loop inside of a thread. This will allow the user to scroll the listview while images are being painted.

Advantages/Disadvantages of the techniques

You should use each technique depending on what you need. The WndProc technique allows you to see items as they are being added. If you are adding thousands of items, it may be slower overall, but at least the user can see what's going on. The pure .NET technique will cause the listview to be blank for a few seconds if you try to add (let's say) 5000 items in the first loop, but if the second loop is in a thread, you do not stop the user from doing other things while the images are being drawn.

One thing to note about the WndProc technique. For some reason, it doesn't work very well if you have a manifest file to use the new XP Themes. I'm not sure why, but some items get erased while others are being drawn. I did find a fix for this (and it is used in source code). Before the loop begins set AutoArrange = false for the listview. When the loop ends, you can set it back to true. Of Course, if you're using Windows XP only, you can use the double buffering technique I described in my previous article (See Intro for link to that). If you have no plans to support XP themes, you do not need to mess with the AutoArrange property.

Note about compiling the source

You will need MS Visual Studio .NET to view this project. After unzipping all the files, there will be two directories, ListViewX and TestListViewFF. Open the solution file in ListViewX folder, and after it loads, set the TestListViewFF project to be the startup project. Then when you compile it should be fine.


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


About the Author

Giovanni Montrone
Web Developer
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionMultiline TextBox Control Flickering Problem in C# Pin
bishnupatro12-Feb-08 18:05
memberbishnupatro12-Feb-08 18:05 
Questionthis.Update() returns right away? Pin
Jimmyyy15-May-06 14:52
memberJimmyyy15-May-06 14:52 
AnswerRe: this.Update() returns right away? Pin
Jimmyyy21-May-06 11:26
memberJimmyyy21-May-06 11:26 
GeneralFlicker Free Pin
caseylara17-Mar-06 11:47
membercaseylara17-Mar-06 11:47 
GeneralRe: Flicker Free Pin
Testo28ß522-Jul-09 12:05
memberTesto28ß522-Jul-09 12:05 
QuestionIt's not working Pin
Ricardo Mendes5-Jan-06 2:07
memberRicardo Mendes5-Jan-06 2:07 
AnswerRe: It's not working Pin
fputil17-Jan-06 6:27
memberfputil17-Jan-06 6:27 
GeneralDoubleBuffered Pin
decoder722-Jan-06 5:44
memberdecoder722-Jan-06 5:44 
GeneralRe: DoubleBuffered Pin
xlay24-May-06 12:02
memberxlay24-May-06 12:02 
GeneralRe: DoubleBuffered Pin
MeNot10-Jul-08 2:17
memberMeNot10-Jul-08 2:17 
GeneralChanging BackColor/ForeColor Flicker Free Pin
chykun18-Aug-05 16:12
memberchykun18-Aug-05 16:12 
GeneralNice! Pin
AndrewVos10-Aug-05 11:45
memberAndrewVos10-Aug-05 11:45 
QuestionHow does it compare with BeginUpdate and EndUpdate Pin
Damien Guard26-Nov-04 1:23
memberDamien Guard26-Nov-04 1:23 
AnswerRe: How does it compare with BeginUpdate and EndUpdate Pin
rshearer25-Jan-05 11:12
memberrshearer25-Jan-05 11:12 
GeneralRe: How does it compare with BeginUpdate and EndUpdate Pin
joachimF22-Nov-06 1:45
memberjoachimF22-Nov-06 1:45 
GeneralI found a better(?) technique Pin
JordanBortz22-Jun-03 18:14
memberJordanBortz22-Jun-03 18:14 
GeneralRe: I found a better(?) technique Pin
Bjørn Reppen6-Jul-03 10:02
sussBjørn Reppen6-Jul-03 10:02 
GeneralIs this technique good only for the list initialization?... Pin
Petru Pau19-Feb-03 0:51
sussPetru Pau19-Feb-03 0:51 
GeneralRe: Is this technique good only for the list initialization?... Pin
Giovanni Montrone19-Feb-03 10:51
memberGiovanni Montrone19-Feb-03 10:51 
GeneralRe: Is this technique good only for the list initialization?... Pin
Petru6620-Feb-03 0:39
memberPetru6620-Feb-03 0:39 
GeneralComparison to SuspendLayout() Pin
Christopher Lord5-Feb-03 6:15
memberChristopher Lord5-Feb-03 6:15 
GeneralRe: Comparison to SuspendLayout() Pin
Giovanni Montrone5-Feb-03 7:29
memberGiovanni Montrone5-Feb-03 7:29 
GeneralRe: Comparison to SuspendLayout() Pin
Christopher Lord5-Feb-03 12:54
memberChristopher Lord5-Feb-03 12:54 
GeneralRe: Comparison to SuspendLayout() Pin
Roger J19-Feb-03 1:34
memberRoger J19-Feb-03 1:34 
GeneralRe: Comparison to SuspendLayout() Pin
mikasa6-Feb-03 7:14
membermikasa6-Feb-03 7:14 

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.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151126.1 | Last Updated 4 Feb 2003
Article Copyright 2003 by Giovanni Montrone
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid