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.
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.
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); }
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); } }
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With