通过 PInvoke 调用 BeginPaint,返回 PAINTSTRUCT 中的空更新区域

Call to BeginPaint via PInvoke returning empty update region in PAINTSTRUCT

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

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

OnPaint 方法中,我试图从 Win32 API 调用 BeginPaint() 来绘制一些形状,但没有绘制任何东西。当我检查 PAINTSTRUCT 结构内的 rcPaint 字段时,它始终为空(所有值为 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);
}

您必须完成 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);
    }
}

我发现了问题。 @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;
            }

        }