如何在更新一个ListViewItem的文本时防止ListView闪烁?

我只想要更新一个ListViewItem的文本,而不会看到任何闪烁。

这是我更新的代码(多次调用):

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

我见过一些涉及覆盖组件的WndProc():解决schemeWndProc():

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

他们说它解决了这个问题,但在我的情况下,它没有 。 我相信这是因为我在每个项目上都使用了图标。

被接受的答案是有效的,但是相当冗长,而且从控制(如其他答案中提到的)中获得的,只是为了启用双缓冲也有点过头了。 幸运的是,如果我们喜欢,我们也可以进行反思,也可以调用内部方法(但是请确定你做了什么!)。

把这个方法封装成一个扩展方法,我们会得到一个相当短的类:

 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 }); } } 

在我们的代码中可以很容易地调用它:

 myListView.DoubleBuffering(true); 

所有的闪烁都消失了。

更新

我偶然发现了这个问题 ,由于这个事实,扩展方法应该(也许)更好:

 public static void DoubleBuffered(this Control control, bool enable) { var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic); doubleBufferPropertyInfo.SetValue(control, enable, null); } 

为了结束这个问题,下面是一个帮助器类,应该在表单中为每个ListView或其他ListView的派生控件加载表单时调用。 感谢“Brian Gillespie”提供的解决scheme。

 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); } } 

CommonControls 6(XP或更新)中的ListView支持双缓冲。 幸运的是,.NET将最新的CommonControls包装在系统上。 要启用双缓冲,发送适当的Windows消息到ListView控件。

这里是详细信息: http : //www.codeproject.com/KB/list/listviewxp.aspx

在.NET Winforms 2.0中,存在名为DoubleBuffered的受保护属性。

通过从ListViewinheritance,那么可以将此protected属性设置为true。 这将启用双缓冲而无需调用SendMessage。

设置DoubleBuffered属性与设置以下样式相同:

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

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

我知道这个问题是相当古老的,但因为这是Google上的第一个search结果之一,我想分享我的修复。

我唯一可以消除闪烁100%的方法是将Oliver(扩展类与双缓冲)和BeignUpdate()EndUpdate()方法的答案结合起来。

这两个人本身都不能为我修正闪烁。 当然,我使用一个非常复杂的列表,我需要推入列表中,也需要几乎每秒更新一次。

这将有助于:

 class DoubleBufferedListView : System.Windows.Forms.ListView { public DoubleBufferedListView() :base() { this.DoubleBuffered = true; } } 

如果您只想更新文本,只需直接设置已更改的SubItem文本,而不是更新整个ListViewItem(您没有说明如何进行更新)。

你所显示的覆盖等同于简单地覆盖OnPaintBackground,这将是一个“更正确的”pipe理方式来完成这个任务,而且它不会帮助单个项目。

如果你仍然有问题,我们需要澄清你的实际尝试。

这是在黑暗中的一个镜头,但你可以尝试双缓冲控制。

 SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true) 

在设置任何列表视图项目之前调用ListView上的BeginUpdate()方法,然后在添加完所有项目后才调用EndUpdate()。

这将停止闪烁。

简单的解决方法是:

yourlistview.BeginUpdate()

//做你的更新添加和删除列表中的项目

yourlistview.EndUpdate()