这个问题可以被认为是使用ownerdraw和virtualmode在listview中闪烁的后续问题。
我在Virtual mode
中有一个ListView
控件,我尝试执行自定义绘图。项目呈现通过以下方法重写完成:
protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs)
如引用的问题中所述,自定义绘图引入了鼠标悬停事件闪烁。调试器告诉我,这是由于触发了过多的自定义绘制事件而发生的。
现在 - 引用问题的公认答案告诉我们:
这是 中的一个错误。NET的列表视图,您无法绕过它 双缓冲。
那么,这些信息的可靠性如何?这真的是一个错误吗?或者,也许我们只是试图切断一部分消息,并希望它不会改变可见的行为?
如果我有我的主人在
Virtual Mode,
ListView
绘制例程,我可以抑制这些Custom Draw
事件并只在WM_PAINT
中执行我的绘图,或者,也许在某些情况下这是不正确的?System.Windows.Forms
控件能够在不改变其初始行为的情况下完成WM_PAINT
中的所有绘画的先决条件是什么?
至少对于 OnDrawItem 的双重缓冲,存在错误是不正确的,但它有点愚蠢:您可以设置一个受保护的属性,但您需要覆盖 ListView。我创建了这样的类:
public class MyListView : ListView
{
public MyListView()
: base()
{
DoubleBuffered = true;
}
}
然后在我的 MyForm.Designer.cs 文件中,我使用以下行更改 ListView 的实例化:
private ListView myListView;
this.myListView = new MyListView();
OnDrawItem 将像魅力一样工作!
我已经在任何自定义呈现事件处理程序(DrawItem,DrawSubItem(中看到ListView控件的闪烁问题。我尝试了BeginUpdate((/EndUpdate((和双缓冲,但没有成功。我认为 .NET 会触发对自定义绘制列右侧所有列的额外WM_PAINT。
但是,我发现此解决方法适用于单个自定义呈现列 ListView。它工作得很好!
- 在列标题编辑器中,将自定义绘制的列设置为最后一列
- 更改所需位置的"显示索引">
这应该可以解决鼠标悬停或运行时渲染中的闪烁问题。
像这里的这个答案,虽然不确定,但,
我认为ListView.BeginUpdate()
和ListView.EndUpdate()
将解决问题。
MSDN 关于此的线程
也许以这种方式:
protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs)
{
ListView.BeginUpdate();
//Do Works Here
ListView.EndUpdate();
}
更新
另一种选择可能是在BackgroundWorker
中使用新线程来更新列表视图...我在我的应用程序中与 BeginUpdate()
/EndUpDate()
一起实现了这一点,发现它比仅BeginUpdate()
/EndUpDate()
更快。
更新
我在SO找到了另一个有效的解决方案,Brian Gillespie
提供的帮助程序类:
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);
}
}