在ListView控件中闪烁(OwnerDraw,Virtual)

此问题可能被视为使用ownerdraw和virtualmode在listview中闪烁的后续行动。

我在Virtual mode有一个ListView控件,我尝试执行自定义绘图。 项目渲染通过以下方法覆盖完成:

 protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs) 

如引用的问题所述,自定义绘图会在鼠标hover事件上引入闪烁。 调试器告诉我这是由于过多的自定义绘制事件被触发而发生的。


现在 – 引用问题的接受答案告诉我们:

这是.NET的ListView中的一个错误,你不能通过双缓冲绕过它。

  • 那么, 这些信息有多可靠? 这真的是一个错误吗? 或者我们可能只是试图切断部分消息并希望它不会改变可见行为?

  • 这是真的,如果我在Virtual Mode,拥有我的所有者绘图例程的ListView Virtual Mode,我可以抑制这些Custom Draw事件,只在WM_PAINT执行我的绘图,或者,在某些情况下这可能是不正确的?

  • System.Windows.Forms控件能够在不改变它的初始行为的情况下完成WM_PAINT所有绘制,有哪些先决条件?

我在任何自定义渲染事件处理程序(DrawItem,DrawSubItem)中都看到了ListView控件的这个闪烁问题。 我尝试了BeginUpdate()/ EndUpdate()和双缓冲没有成功。 我认为.NET会向自定义绘制列右侧的所有列触发其他WM_PAINT。

但是我发现这个解决方法是一个自定义渲染列ListView。 它工作得很好!

  1. 在columnheader编辑器中,将自定义绘制列设置为最后一列
  2. 更改所需位置的“DisplayIndex”

这应该可以解决鼠标hover或运行时渲染中的闪烁问题。

至少对于OnDrawItem的双缓冲,有一个错误是错误的,但它有点愚蠢:你可以设置一个受保护的属性,但你需要覆盖ListView。 我创建了这种类:

 public class MyListView : ListView { public MyListView() : base() { DoubleBuffered = true; } } 

然后在我的MyForm.Designer.cs文件中,我使用以下行更改ListView的实例化:

 private ListView myListView; this.myListView = new MyListView(); 

OnDrawItem将像魅力一样工作!

喜欢这里的答案 ,虽然不确定但是,

我认为ListView.BeginUpdate()ListView.EndUpdate()将解决问题。

关于这个的MSDN主题

也许以这种方式:

 protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs) { ListView.BeginUpdate(); //Do Works Here ListView.EndUpdate(); } 

更新

另一个替代方案可能是在BackgroundWorker使用一个新的线程来更新ListView …我在我的应用程序中实现了这个以及BeginUpdate() / EndUpDate() ,发现它比只有BeginUpdate() / EndUpDate()速度快。

更新

我在SO发现了另一个有效的解决方案 ,一个由Brian Gillespie提供的助手类:

 public enum ListViewExtendedStyles { ///  /// LVS_EX_GRIDLINES ///  GridLines = 0x00000001, ///  /// LVS_EX_SUBITEMIMAGES ///  SubItemImages = 0x00000002, ///  /// LVS_EX_CHECKBOXES ///  CheckBoxes = 0x00000004, ///  /// LVS_EX_TRACKSELECT ///  TrackSelect = 0x00000008, ///  /// LVS_EX_HEADERDRAGDROP ///  HeaderDragDrop = 0x00000010, ///  /// LVS_EX_FULLROWSELECT ///  FullRowSelect = 0x00000020, ///  /// LVS_EX_ONECLICKACTIVATE ///  OneClickActivate = 0x00000040, ///  /// LVS_EX_TWOCLICKACTIVATE ///  TwoClickActivate = 0x00000080, ///  /// LVS_EX_FLATSB ///  FlatsB = 0x00000100, ///  /// LVS_EX_REGIONAL ///  Regional = 0x00000200, ///  /// LVS_EX_INFOTIP ///  InfoTip = 0x00000400, ///  /// LVS_EX_UNDERLINEHOT ///  UnderlineHot = 0x00000800, ///  /// LVS_EX_UNDERLINECOLD ///  UnderlineCold = 0x00001000, ///  /// LVS_EX_MULTIWORKAREAS ///  MultilWorkAreas = 0x00002000, ///  /// LVS_EX_LABELTIP ///  LabelTip = 0x00004000, ///  /// LVS_EX_BORDERSELECT ///  BorderSelect = 0x00008000, ///  /// LVS_EX_DOUBLEBUFFER ///  DoubleBuffer = 0x00010000, ///  /// LVS_EX_HIDELABELS ///  HideLabels = 0x00020000, ///  /// LVS_EX_SINGLEROW ///  SingleRow = 0x00040000, ///  /// LVS_EX_SNAPTOGRID ///  SnapToGrid = 0x00080000, ///  /// LVS_EX_SIMPLESELECT ///  SimpleSelect = 0x00100000 } public enum ListViewMessages { First = 0x1000, SetExtendedStyle = (First + 54), GetExtendedStyle = (First + 55), } ///  /// Contains helper methods to change extended styles on ListView, including enabling double buffering. /// Based on Giovanni Montrone's article on  ///  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); } }