Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent flickering in ListView when updating a single ListViewItem's text?

All I want is to update an ListViewItem's text whithout seeing any flickering.

This is my code for updating (called several times):

listView.BeginUpdate();
listViewItem.SubItems[0].Text = state.ToString();    // update the state
listViewItem.SubItems[1].Text = progress.ToString(); // update the progress
listView.EndUpdate();

I've seen some solutions that involve overriding the component's WndProc():

protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM.WM_ERASEBKGND)
    {
        m.Msg = (int)IntPtr.Zero;
    }
    base.WndProc(ref m);
}

They say it solves the problem, but in my case It didn't. I believe this is because I'm using icons on every item.

like image 880
Jonas Avatar asked Sep 17 '08 21:09

Jonas


4 Answers

The accepted answer works, but is quite lengthy, and deriving from the control (like mentioned in the other answers) just to enable double buffering is also a bit overdone. But fortunately we have reflection and can also call internal methods if we like to (but be sure what you do!).

Be encapsulating this approach into an extension method, we'll get a quite short class:

public static class ControlExtensions {     public static void DoubleBuffering(this Control control, bool enable)     {         var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);         method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });     } } 

Which can easily be called within our code:

InitializeComponent();  myListView.DoubleBuffering(true); //after the InitializeComponent(); 

And all flickering is gone.

Update

I stumbled on this question and due to this fact, the extension method should (maybe) better be:

public static void DoubleBuffered(this Control control, bool enable) {     var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);     doubleBufferPropertyInfo.SetValue(control, enable, null); } 
like image 133
Oliver Avatar answered Oct 06 '22 09:10

Oliver


To end this question, here is a helper class that should be called when the form is loading for each ListView or any other ListView's derived control in your form. Thanks to "Brian Gillespie" for giving the solution.

public enum ListViewExtendedStyles {     /// <summary>     /// LVS_EX_GRIDLINES     /// </summary>     GridLines = 0x00000001,     /// <summary>     /// LVS_EX_SUBITEMIMAGES     /// </summary>     SubItemImages = 0x00000002,     /// <summary>     /// LVS_EX_CHECKBOXES     /// </summary>     CheckBoxes = 0x00000004,     /// <summary>     /// LVS_EX_TRACKSELECT     /// </summary>     TrackSelect = 0x00000008,     /// <summary>     /// LVS_EX_HEADERDRAGDROP     /// </summary>     HeaderDragDrop = 0x00000010,     /// <summary>     /// LVS_EX_FULLROWSELECT     /// </summary>     FullRowSelect = 0x00000020,     /// <summary>     /// LVS_EX_ONECLICKACTIVATE     /// </summary>     OneClickActivate = 0x00000040,     /// <summary>     /// LVS_EX_TWOCLICKACTIVATE     /// </summary>     TwoClickActivate = 0x00000080,     /// <summary>     /// LVS_EX_FLATSB     /// </summary>     FlatsB = 0x00000100,     /// <summary>     /// LVS_EX_REGIONAL     /// </summary>     Regional = 0x00000200,     /// <summary>     /// LVS_EX_INFOTIP     /// </summary>     InfoTip = 0x00000400,     /// <summary>     /// LVS_EX_UNDERLINEHOT     /// </summary>     UnderlineHot = 0x00000800,     /// <summary>     /// LVS_EX_UNDERLINECOLD     /// </summary>     UnderlineCold = 0x00001000,     /// <summary>     /// LVS_EX_MULTIWORKAREAS     /// </summary>     MultilWorkAreas = 0x00002000,     /// <summary>     /// LVS_EX_LABELTIP     /// </summary>     LabelTip = 0x00004000,     /// <summary>     /// LVS_EX_BORDERSELECT     /// </summary>     BorderSelect = 0x00008000,     /// <summary>     /// LVS_EX_DOUBLEBUFFER     /// </summary>     DoubleBuffer = 0x00010000,     /// <summary>     /// LVS_EX_HIDELABELS     /// </summary>     HideLabels = 0x00020000,     /// <summary>     /// LVS_EX_SINGLEROW     /// </summary>     SingleRow = 0x00040000,     /// <summary>     /// LVS_EX_SNAPTOGRID     /// </summary>     SnapToGrid = 0x00080000,     /// <summary>     /// LVS_EX_SIMPLESELECT     /// </summary>     SimpleSelect = 0x00100000 }  public enum ListViewMessages {     First = 0x1000,     SetExtendedStyle = (First + 54),     GetExtendedStyle = (First + 55), }  /// <summary> /// Contains helper methods to change extended styles on ListView, including enabling double buffering. /// Based on Giovanni Montrone's article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/> /// </summary> public class ListViewHelper {     private ListViewHelper()     {     }      [DllImport("user32.dll", CharSet = CharSet.Auto)]     private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);      public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)     {         ListViewExtendedStyles styles;         styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);         styles |= exStyle;         SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);     }      public static void EnableDoubleBuffer(Control control)     {         ListViewExtendedStyles styles;         // read current style         styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);         // enable double buffer and border select         styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;         // write new style         SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);     }     public static void DisableDoubleBuffer(Control control)     {         ListViewExtendedStyles styles;         // read current style         styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);         // disable double buffer and border select         styles -= styles & ListViewExtendedStyles.DoubleBuffer;         styles -= styles & ListViewExtendedStyles.BorderSelect;         // write new style         SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);     } } 
like image 21
Jonas Avatar answered Oct 06 '22 08:10

Jonas


The ListView in CommonControls 6 (XP or newer) supports double buffering. Fortunately, .NET wraps the newest CommonControls on the system. To enable double buffering, send the appropriate Windows message to the ListView control.

Here are the details: http://www.codeproject.com/KB/list/listviewxp.aspx

like image 23
Brian Gillespie Avatar answered Oct 06 '22 08:10

Brian Gillespie


In .NET Winforms 2.0 there exist a protected property called DoubleBuffered.

By inheriting from ListView, then one can set this protected property to true. This will enable double buffering without needing to call SendMessage.

Setting the DoubleBuffered property is the same as setting the following style:

listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94096

like image 32
Rolf Kristensen Avatar answered Oct 06 '22 08:10

Rolf Kristensen