画上一个列表视图禁用列表视图项重绘视图、列表、画上、项重绘

2023-09-07 00:55:02 作者:我比较没用

有什么原因?

我重写OnPaintBackground并绘制一个字符串。它不出现,直到我把这种在构造函数中:

  this.SetStyle(ControlStyles.UserPaint,真正的);
 

但我没有看到在列表视图中的项目。

为什么和如何解决此问题?

编辑:code

 保护覆盖无效OnPaintBackground(PaintEventArgs的pevent)
{
base.OnPaintBackground(pevent);

//创建字符串来绘制。
字符串抽绳=76;

//创建字体和刷子。
字体drawFont =新的字体(宋体,36);
SolidBrush drawBrush =新SolidBrush(Color.Blue);

//创建点图的左上角。
的PointF drawPoint =新的PointF(150.0F,150.0F);

//绘制字符串到屏幕。
pevent.Graphics.DrawString(抽绳,drawFont,drawBrush,drawPoint);

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

解决方案

正如我在关于这个问题的最后一个线程说,的OnPaint() UserPaint 不ListView的工作。画在由基础的控制处理,并且不能在该方式截获。这是不同于其他控件

所以,当 ControlStyles.UserPaint ,底层控制没有告诉重绘自身。相反,所有绘图发送到 OnPaintBackground()的OnPaint()方法,它 - 因为你已经找到 - 没做什么。

自定义视图

有两种方法可以做到你的要求(第二个比第一个好):

第一种方法:拦截 WM_PAINT ,做基础处理,然后绘制到列表视图。事情是这样的:

 公共类MyListView:ListView控件
{
    保护覆盖无效的WndProc(参考消息M){
        开关(m.Msg){
            案例为0x0F:// WM_PAINT
                this.HandlePaint(REF米);
                打破;
            默认:
                base.WndProc(REF米);
                打破;
        }
    }

    受保护的虚拟无效HandlePaint(参考消息M){
        base.WndProc(REF米);

        使用(图形G = this.CreateGraphics()){
            的StringFormat SF =新的StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            sf.Trimming = StringTrimming.EllipsisCharacter;
            g.DrawString(一些文本,新的字体(宋体,13),
                SystemBrushes.ControlDark,this.ClientRectangle,SF);
        }
    }
}
 

不过,这给重绘问题,当你得出的结论就是在ListView认为保持控制的内容,在禁区外 - 它不会触发漆事件

二方式:拦截CustomDraw通知(这是的没有的一样的OwnerDraw),并听取了 CDDS_POSTPAINT 阶段。在这个阶段,你可以放心地绘制到列表视图。你可以看一下 ObjectListView 的code怎么看它完成。

您也可以直接节省大量的麻烦,直接使用ObjectListView:)

What's the reason for this?

I override OnPaintBackground and draw a string. It doesn't show up until I call this in the constructor:

this.SetStyle ( ControlStyles.UserPaint, true );

But then I don't see the items in the listview.

Why and how to solve this?

EDIT: code

	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`

解决方案

As I said in the last thread about this subject, OnPaint() and UserPaint don't work with ListView. The painting is handled by the underlying control and cannot be intercepted in that fashion. This is different to other Controls

So, when ControlStyles.UserPaint is true, the underlying control is not told to redraw itself. Instead, all drawing is routed to the OnPaintBackground() and OnPaint() methods, which -- as you have found -- do nothing.

There are two ways to do what you asked (the second is better than the first):

First way: Intercept the WM_PAINT, do the base processing, and then draw onto the listview. Something like this:

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);
        }
    }
}

But this gives repaint problems when what you draw is outside the area that the listview thinks holds the control's contents -- it doesn't trigger paint events.

Second manner: Intercept the CustomDraw notification (this is not the same as OwnerDraw), and listen for the CDDS_POSTPAINT stage. In that stage you can safely draw onto the list view. You can look at the code of ObjectListView to see how it is done.

You could also just save yourself a lot of bother and use an ObjectListView directly :)

 
精彩推荐