Robert S.
Robert S.

Reputation: 2042

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.

Found the problem

In my project there is a graphical overlay class which connects Paint event handlers to all controls in my form (the whole hierarchy). In this handler a transformation is performed. This graphical overlay kept me sleepless so many times. I guess I will remove it.

Upvotes: 1

Views: 450

Answers (1)

Luaan
Luaan

Reputation: 63742

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, ...).

Upvotes: 2

Related Questions