views:

4530

answers:

6

I have a list view that is periodically updated (every 60 seconds). It was anoying to me that i would get a flicker every time it up dated. The method being used was to clear all the items and then recreate them. I decided to instead of clearing the items I would just write directly to the cell with the new text. Is this a better approach or does anyone have a better solution.

Thanks

Brad

+13  A: 

The ListView control has a flicker issue. The problem appears to be that the control's Update overload is improperly implemented such that it acts like a Refresh. An Update should cause the control to redraw only its invalid regions whereas a Refresh redraws the control’s entire client area. So if you were to change, say, the background color of one item in the list then only that particular item should need to be repainted. Unfortunately, the ListView control seems to be of a different opinion and wants to repaint its entire surface whenever you mess with a single item… even if the item is not currently being displayed. So, anyways, you can easily suppress the flicker by rolling your own as follows:

class ListViewNF : System.Windows.Forms.ListView
{
    public ListViewNF()
    {
        //Activate double buffering
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        this.SetStyle(ControlStyles.EnableNotifyMessage, true);
    }

    protected override void OnNotifyMessage(Message m)
    {
        //Filter out the WM_ERASEBKGND message
        if(m.Msg != 0x14)
        {
            base.OnNotifyMessage(m);
        }
    }
}

From: Geekswithblogs.net

Stormenet
You have to know that the downside of this solution (due to the double buffering) is that updating the control is significantly slower (try adding a 1000 items).
Sandor Drieënhuizen
To be honest, I never use the winforms listview. But isn't that perfomance loss away when you call **SuspendLayout** and **ResumeLayout**?
Stormenet
+2  A: 

Yes, make it double buffered. It will reduce the flicker ;) http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.doublebuffered.aspx

Gonzalo Quero
-1: You can't set a `ListView`s DoubleBuffered property (it's protected).
Jon Cage
A: 

Try setting the double buffered property in true.

Also you could use:

this.SuspendLayout();

//update control

this.ResumeLayout(False);

this.PerformLayout();
Ironicnet
Layout mainly applies when moving/resizing things... I suspect you mean [Begin|End]Update, as per my reply.
Marc Gravell
+4  A: 

In addition to the other replies, many controls have a [Begin|End]Update() method that you can use to reduce flickering when editing the contents - for example:

    listView.BeginUpdate();
    try {
        // listView.Items... (lots of editing)
    } finally {
        listView.EndUpdate();
    }
Marc Gravell
+1: Thanks; this made a noticable difference :-)
Jon Cage
A: 

Perfect!!! works great!!!!!!!!!!!!!!!!! thanks Stormenet

tomassino
+2  A: 

Excellent question and Stormenent's answer was spot on. Here's a C++ port of his code for anyone else who might be tackling C++/CLI implementations.

#pragma once

#include "Windows.h" // For WM_ERASEBKGND

using namespace System;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;

public ref class FlickerFreeListView : public ListView
{
public:
    FlickerFreeListView()
    {
        //Activate double buffering
        SetStyle(ControlStyles::OptimizedDoubleBuffer | ControlStyles::AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        SetStyle(ControlStyles::EnableNotifyMessage, true);
    }

protected:
    virtual  void OnNotifyMessage(Message m) override
    {
        //Filter out the WM_ERASEBKGND message
        if(m.Msg != WM_ERASEBKGND)
        {
            ListView::OnNotifyMessage(m);
        }
    }

};
Jon Cage