我对 Jeffery Tan 在该帖子中的回答感到惊讶。他的解决方案无法工作,因为代码试图在标题控件客户区域之外绘制。在自定义绘图(以及所有者绘图)中使用的hDC 用于控件的客户区,因此不能用于在非客户区进行绘制。标题控件中最右侧列的右侧区域位于非客户区。所以你需要一个不同的解决方案。
可能的解决方案
- 高科技且部分有效
您可以使用GetDC() WinAPI 调用在客户区之外启用绘图:
[System.Runtime.InteropServices.DllImport("user32")]
private static extern IntPtr GetDC(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("user32")]
private static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);
public static IntPtr GetHeaderControl(ListView list) {
const int LVM_GETHEADER = 0x1000 + 31;
return SendMessage(list.Handle, LVM_GETHEADER, 0, 0);
}
在您的列绘制事件处理程序中,您将需要这样的东西:
if (e.ColumnIndex == 3) //last column index
{
ListView lv = e.Header.ListView;
IntPtr headerControl = NativeMethods.GetHeaderControl(lv);
IntPtr hdc = GetDC(headerControl);
Graphics g = Graphics.FromHdc(hdc);
// Do your extra drawing here
Rectangle rc = new Rectangle(e.Bounds.Right, //Right instead of Left - offsets the rectangle
e.Bounds.Top,
e.Bounds.Width,
e.Bounds.Height);
e.Graphics.FillRectangle(Brushes.Red, rc);
g.Dispose();
ReleaseDC(headerControl, hdc);
}
但是这样做的问题是,由于您的绘图在客户区域之外,Windows 并不总是知道应该何时绘制它。所以它有时会消失,然后在Windows认为需要重新绘制标题时重新绘制。
- 技术含量低但丑
向您的控件添加一个额外的空列,所有者可以随意绘制它,使其非常宽,并关闭水平滚动(可选)。
我知道这很可怕,但您正在寻找建议 :)
- 最有效,但仍不完美
使用ObjectListView。这个 .NET ListView 的包装器允许您将覆盖添加到列表中——覆盖可以在 ListView 中的任何位置绘制,包括标题。 【声明:我是ObjectListView的作者,但我还是觉得是最好的解决方案】
public class HeaderOverlay : AbstractOverlay
{
public override void Draw(ObjectListView olv, Graphics g, Rectangle r) {
if (olv.View != System.Windows.Forms.View.Details)
return;
Point sides = NativeMethods.GetColumnSides(olv, olv.Columns.Count-1);
if (sides.X == -1)
return;
RectangleF headerBounds = new RectangleF(sides.Y, 0, r.Right - sides.Y, 20);
g.FillRectangle(Brushes.Red, headerBounds);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
g.DrawString("In non-client area!", new Font("Tahoma", 9), Brushes.Black, headerBounds, sf);
}
}
这给出了这个:
[阅读这个答案,我认为这是一个努力尝试的例子 :) 希望你在这里找到一些有用的东西。]