通过PInvoke调用BeginPaint返回PAINTSTRUCT

时间:2016-11-21 20:03:31

标签: c# winforms winapi pinvoke

我一直致力于创建自定义RichTextBox控件,以便为文本区域添加一些额外的图形。根据我一直在阅读的内容,此控件默认情况下不会公开其Paint事件。

我按照MSDN上的建议(Painting on a RichTextBox Control )重新公开了Paint事件,并创建了一个由OnPaint消息触发的WM_PAINT事件处理程序。

OnPaint方法中,我试图从Win32 API调用BeginPaint()来绘制一些形状,但没有绘制任何形状。当我检查rcPaint结构内的PAINTSTRUCT字段时,它总是为空(所有值都为0)。所以我的问题是,为什么更新区域总是空的?我一定错过了什么。

相关代码:

public partial class RichTextBoxEnhanced : RichTextBox
{

    private PAINTSTRUCT ps;


    new public void OnPaint(PaintEventArgs e)
    {
        var hdc = BeginPaint(this.Handle,  out ps);

        FillRect(hdc, ref ps.rcPaint, CreateSolidBrush(100));

        Rectangle(hdc, 1000, 2000, 1000, 2000);

        EndPaint(this.Handle, ref ps);

        Paint?.Invoke(this, e);
    }

    [DllImport("user32.dll")]
    static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint);

    [DllImport("user32.dll")]
    static extern bool EndPaint(IntPtr hWnd, [In] ref PAINTSTRUCT lpPaint);

    [DllImport("gdi32.dll")]
    static extern IntPtr CreateSolidBrush(uint crColor);
}

2 个答案:

答案 0 :(得分:1)

您必须浏览WndProc并允许控件执行默认绘制。您可以使用Graphics对象进行绘画。例如:

public partial class MyRichEdit : RichTextBox
{
    public MyRichEdit()
    {
        InitializeComponent();
    }

    protected override void WndProc(ref Message msg)
    {
        switch (msg.Msg)
        {
            case 15://WM_PAINT
                base.WndProc(ref msg);
                Graphics g = Graphics.FromHwnd(Handle);
                Pen pen = new Pen(Color.Red);
                g.DrawRectangle(pen, 0, 0, 10, 10);
                return;
        }
        base.WndProc(ref msg);
    }
}

答案 1 :(得分:0)

我发现了这个问题。 @andlabs评论让我看看我被覆盖的WndProc方法。我的绘画方法是在base.WndProc(ref msg)之后调用的,它显然执行BeginPaint。移动我上面的OnPaint()方法可以解决问题。

错误的代码:

protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_PAINT:
                    mBaseControl.Invalidate();
                    base.WndProc(ref m);
                    OnPaint();
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }

        }

正确的代码:

protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_PAINT:
                    mBaseControl.Invalidate();
                    OnPaint();
                    base.WndProc(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }

        }