【问题标题】:Painting on a listview disables the redraw on listview items在列表视图上绘画会禁用列表视图项目的重绘
【发布时间】:2009-10-25 14:27:46
【问题描述】:

这是什么原因?

我覆盖 OnPaintBackground 并绘制一个字符串。直到我在构造函数中调用它才会显示:

this.SetStyle ( ControlStyles.UserPaint, true );

但是我在列表视图中看不到项目。

为什么以及如何解决这个问题?

编辑:代码

    protected override void OnPaintBackground ( PaintEventArgs pevent )
    {
        base.OnPaintBackground ( pevent );

        // Create string to draw.
        String drawString = "76";

        // Create font and brush.
        Font drawFont = new Font ( "Arial", 36 );
        SolidBrush drawBrush = new SolidBrush ( Color.Blue );

        // Create point for upper-left corner of drawing.
        PointF drawPoint = new PointF ( 150.0F, 150.0F );

        // Draw string to screen.
        pevent.Graphics.DrawString ( drawString, drawFont, drawBrush, drawPoint );

        //pevent.Graphics.FillRectangle ( drawBrush, this.ClientRectangle );
    }`enter code here`

【问题讨论】:

  • 你在调用base.OnPaintBackground()吗?您可以发布您覆盖的代码吗?
  • 以下属性和样式的值是多少? - ControlStyles.DoubleBuffer - ControlStyles.AllPaintingInWmPaint - ListView.OwnerDraw
  • @Sheng,仅此而已。我刚刚添加了 UserPaint,仅此而已。

标签: c# .net winforms listview gdi+


【解决方案1】:

正如我在上一篇关于这个主题的帖子中所说,OnPaint()UserPaint 不适用于 ListView。绘画由底层控件处理,不能以这种方式被拦截。这与其他控件不同

因此,当ControlStyles.UserPainttrue 时,不会告知底层控件重绘自身。相反,所有绘图都被路由到OnPaintBackground()OnPaint() 方法,正如您所发现的那样,它们什么都不做。

有两种方法可以按照您的要求进行操作(第二种比第一种更好):

第一种方式:截取WM_PAINT,做基础处理,然后绘制到listview上。像这样的:

public class MyListView : ListView
{
    protected override void WndProc(ref Message m) {
        switch (m.Msg) {
            case 0x0F: // WM_PAINT
                this.HandlePaint(ref m);
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }

    protected virtual void HandlePaint(ref Message m) {
        base.WndProc(ref m);

        using (Graphics g = this.CreateGraphics()) {
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            sf.Trimming = StringTrimming.EllipsisCharacter;
            g.DrawString("Some text", new Font("Tahoma", 13),
                SystemBrushes.ControlDark, this.ClientRectangle, sf);
        }
    }
}

但是,当您绘制的内容超出列表视图认为包含控件内容的区域时,这会导致重绘问题——它不会触发绘制事件。

第二种方式:拦截CustomDraw通知(这和OwnerDraw一样),监听CDDS_POSTPAINT阶段。在那个阶段,您可以安全地绘制到列表视图上。大家可以看看ObjectListView的代码,看看是怎么做的。

您也可以省去很多麻烦,直接使用 ObjectListView :)

【讨论】:

  • 谢谢语法,我会切换到你的列表视图。
  • 顺便说一句,我刚刚切换到您的列表视图,这很棒。但是在鼠标点击测试中遇到了一个强制转换异常,尽管我没有在代码中使用这些事件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-22
  • 2011-05-03
  • 2017-02-11
  • 1970-01-01
  • 2011-02-09
相关资源
最近更新 更多