Robert S. Robert S. - 1 month ago 19
C# Question

base.OnPaint order changes drawing location

I have a strange problem. I made my own user control deriving from

UserControl
. I override
OnPaint
. Now I draw something in
OnPaint
. Let's say at position 0, 0.

If I call
base.OnPaint
after my custom drawing everything is fine. But if I call
base.OnPaint
before the stuff I'm drawing, it seems to ignore the containing control and the location is relative to the form instead of relative to the client area of the parent control. So when I draw at position (0, 0) it will effectively be drawn at negative x and y and I will only see a part of it. The
base.OnPaint
is
UserControl.OnPaint
. So I don't call my code there.

Here is an example:

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);

var rect = new System.Drawing.Rectangle(this.ClientSize.Width - 16,
this.ClientSize.Height - 16, 16, 16);

e.Graphics.FillRectangle(new System.Drawing.SolidBrush(System.Drawing.Color.Red), rect);

//base.OnPaint(e);
}


In this case the red rectangle is displayed somewhere inside the client area but not at the lower right corner. If I uncomment the last line and comment the first line the red rectangle is displayed at the lower right corner as expected.

I don't get it. I did this many times and it always worked. So I tried to find any differences. The only I found is that I don't add my control in the designer but add it programmatically to another control with
theContainingControl.Controls.Add(myMessedUpControl);
.

This also happens for every parent-child-level I add. So if I create another control (another class) and also override
OnPaint
the behavior is the same if I add it to another user control.

Does anyone had this behavior before? How can I fix this? The problem is that I want to call
base.OnPaint
first and also everyone suggest this. But as I said I can't without messing the coordinates up.

One note: The coordinates are really 0, 0 in the debugger at the draw calls like
DrawLine
,
DrawImage
oder
DrawString
. But the result is displayed at negative coordinates (relative to the client area). It looks like the client coordinates are interpreted as client coordinates of the form. But I don't know why.

Answer

The Graphics object has a lot of mutable state. The order of operations matters if you mess with this mutable state - for example, you can use the Transform matrix to change the offset of everything rendered on the surface.

It sounds like your ascendant changes one of those during its own OnPaint handler without resetting it back. Try doing a e.Graphics.ResetTransform(); before you start your own painting. Make sure all the other state is also the way you want it (clip, DPI, ...).