为 TreeView 和 ListView 控件生成缺失的 Paint 事件






4.77/5 (24投票s)
2003年7月15日
2分钟阅读

178618

1651
关于为TreeView和ListView生成缺失Paint事件的文章
引言
Microsoft .NET 窗体控件,如TreeView
和Listview
,只是对ComCtl中控件的封装。因此,它们通常不会引发Paint
事件。我所见到的唯一建议是设置ControlStyles.UserPaint
样式,并自己完成所有绘制!
TreeViewWithPaint 控件
为了解决这个问题,使用了基于Bitmap
的内部Graphics
对象。它会在任何Resize
期间重新创建。
//Recreate internal graphics object
protected override void OnResize( System.EventArgs e ) {
if( internalBitmap == null ||
internalBitmap.Width != Width || internalBitmap.Height != Height ) {
if( Width != 0 && Height != 0 ) {
DisposeInternal();
internalBitmap = new Bitmap( Width, Height );
internalGraphics = Graphics.FromImage( internalBitmap );
}
}
}
当控件收到WM_PAINT
时,将执行三个步骤
- ComCtl 通过
WM_PRINTCLIENT
消息绘制到内部Graphics
对象中。//Draw Internal Graphics IntPtr hdc = internalGraphics.GetHdc(); Message printClientMessage = Message.Create( Handle, WM_PRINTCLIENT, hdc, IntPtr.Zero ); DefWndProc( ref printClientMessage ); internalGraphics.ReleaseHdc( hdc );
- 现在使用从内部
Graphics
对象构造的PaintEventArgs
触发OnPaint()
。//Add the missing OnPaint() call OnPaint( new PaintEventArgs( internalGraphics, Rectangle.FromLTRB( updateRect.left, updateRect.top, updateRect.right, updateRect.bottom ) ) );
- 内部
Graphics
对象的Bitmap
复制到正常的屏幕Graphics
设备。//Draw Screen Graphics screenGraphics.DrawImage( internalBitmap, 0, 0 );
此外,过滤掉了 WM_ERASEBKGND
以消除闪烁。
case WM_ERASEBKGND:
//removes flicker
return;
此外,添加了 Paint
事件以恢复可浏览的属性。
[
//Re-enable Attributes for the Paint Event
EditorBrowsableAttribute( EditorBrowsableState.Always ),
BrowsableAttribute(true)
]
public new event PaintEventHandler Paint {
add { base.Paint += value; }
remove{ base.Paint -= value; }
}
Using the Code
要使用 TreeViewWithPaint
控件
- 只需将控件添加到工具箱即可。
- 将其拖放到您的窗体上。
- 将一个
Paint
处理程序附加到现在公开的Paint
事件。
要创建一个 <AnotherComCtl>WithPaint
,请按如下方式修改 TreeViewWithPaint
- 使用
<AnotherComCtl>
作为基类。 - 将
<AnotherComCtl>
类的属性复制到<AnotherComCtl>WithPaint
类。 - 添加一个 <AnotherComCtl>WithPaint.bmp,这是一个用于工具箱图标的 16x16 位图。
TreeViewWithPaint 控件测试平台
我创建了一个包含单个 TreeViewWithPaint
控件的简单 Form
。现在可以使用 Paint
事件。
treeViewWithPaint1.Paint += new PaintEventHandler(
treeViewWithPaint1_Paint );
这个特定的 Paint
处理程序只是在选定的节点内部绘制一个简单的白色带。
//Add a simple yellow band inside the selected node
private void treeViewWithPaint1_Paint(object sender, PaintEventArgs e) {
Graphics g = e.Graphics;
TreeNode node = treeViewWithPaint1.SelectedNode;
if( node != null && node.IsVisible ) {
using( Pen pen = new Pen( Color.Yellow ) ) {
g.DrawRectangle( pen,
node.Bounds.X + 1,
node.Bounds.Y + 1,
node.Bounds.Width - 3,
node.Bounds.Height - 3
);
}
}
}
关注点
- 所需的属性是通过使用 VB(而不是 C#)对象浏览器为 VS 2002(而不是 VS 2003)发现的。
- XP 有一个未公开的功能,即如果您在设计时添加项目,则会在
TreeView
上显示水平滚动条。
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。