我正在使用带有以下参数设置的listview控件:
this.listView1.BackColor = System.Drawing.Color.Gainsboro;
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2});
this.listView1.FullRowSelect = true;
this.listView1.HideSelection = false;
this.listView1.Location = new System.Drawing.Point(67, 192);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(438, 236);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
this.listView1.DrawColumnHeader += new System.Windows.Forms.DrawListViewColumnHeaderEventHandler(this.listView1_DrawColumnHeader);
this.listView1.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listView1_RetrieveVirtualItem);
this.listView1.DrawSubItem += new System.Windows.Forms.DrawListViewSubItemEventHandler(this.listView1_DrawSubItem);向两行提供一些随机文本。Ownerdrawing很简单:
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
if (e.ColumnIndex == 0)
{
e.DrawBackground();
e.DrawText();
}
else
e.DrawDefault = true;
//Console.WriteLine("{0}\t\tBounds:{1}\tItem:{2}\tSubitem:{3}", (i++).ToString(), e.Bounds.ToString(), e.Item, e.SubItem);
}问题是:当我将鼠标悬停在listview的内容上时,我得到了第一列的闪烁。调试显示,当鼠标悬停在DrawSubItem上时,会不断地调用它。
是bug吗?如何避免这种行为?
发布于 2009-06-02 15:27:06
这是.NET的ListView中的一个错误,您不能通过双缓冲来绕过它。
在虚拟列表中,当鼠标悬停在列0上时,底层控件会生成大量自定义绘制事件。即使启用了DoubleBuffering,这些自定义绘制事件也会导致闪烁,因为它们是在正常的WmPaint消息之外发送的。
我似乎还记得这只发生在XP上。Vista修复了这个问题(但也引入了其他问题)。
您可以查看ObjectListView中的代码,了解它是如何解决这个问题的。
如果你想自己解决这个问题,你需要深入研究ListView控件的内部机制:
如下所示::
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case 0x0F: // WM_PAINT
this.isInWmPaintMsg = true;
base.WndProc(ref m);
this.isInWmPaintMsg = false;
break;
case 0x204E: // WM_REFLECT_NOTIFY
NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR));
if (nmhdr.code == -12) { // NM_CUSTOMDRAW
if (this.isInWmPaintMsg)
base.WndProc(ref m);
} else
base.WndProc(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}发布于 2009-11-05 19:52:56
我收到了一堆
'System.Drawing.NativeMethods' is inaccessible due to its protection level和
The type name 'NMHDR' does not exist in the type 'System.Drawing.NativeMethods' 错误。我在某处读到我必须包含user32.dll,但不知道在这种情况下该怎么做。
编辑:好的,我甚至在开始思考之前就发布了。现在,我创建了自己的ListView控件,并复制了objectListView代码中的结构。它现在似乎起作用了。下面是我的代码:
public class Listview : ListView
{
private bool isInWmPaintMsg=false;
[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public IntPtr idFrom;
public int code;
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x0F: // WM_PAINT
this.isInWmPaintMsg = true;
base.WndProc(ref m);
this.isInWmPaintMsg = false;
break;
case 0x204E: // WM_REFLECT_NOTIFY
NMHDR nmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));
if (nmhdr.code == -12)
{ // NM_CUSTOMDRAW
if (this.isInWmPaintMsg)
base.WndProc(ref m);
}
else
base.WndProc(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
}发布于 2009-06-02 15:01:04
我不能为ListView频繁调用自定义绘制事件提供解决方案,但也许你可以用双缓冲来掩盖这个问题:
Stackoverflow: How to double buffer .NET controls on a form?
https://stackoverflow.com/questions/938896
复制相似问题