I have been working on creating a custom RichTextBox
control to add some additional graphics to the text area. From what I've been reading, this control does not expose its Paint event by default.
I followed a suggestion on MSDN (Painting on a RichTextBox Control ) to re-expose the Paint event and create an OnPaint
event handler which is triggered by the WM_PAINT
message.
In the OnPaint
method, I'm trying to call BeginPaint()
from the Win32 API to draw some shapes, but nothing is being drawn. When I inspect the rcPaint
field inside of the PAINTSTRUCT
struct, it's always empty (all values are 0). So my question is, why is the update region always empty? I must be missing something.
Relevant code:
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);
}
I found the issue. @andlabs comment lead me to look at my overridden WndProc
method. My painting method was called after base.WndProc(ref msg)
which apparently performs BeginPaint
. Moving my OnPaint()
method above corrected the issue.
Wrong code:
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;
}
}
Correct code:
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;
}
}