c# - I can't break out of my ClipRectangle and I want to cry

winforms custom-controls (2)

When overriding the OnPaint method of a custom control I'm supplied with a PaintEventArgs, which contains a Graphics object and a ClipRectangle. The ClipRectangle is too small for my tastes and so I want to either extend it by say, 100 pixels, or ignore it completely.

No matter what I do, I can't seem to break out of the ClipRectangle. So far I've tried:

e.ClipRectangle.Inflate(100, 0);
e.Graphics.SetClip(new Rectangle(x, y, w, h));

The parent control is calling Invalidate(true) (to force an invalidation of all the childs' child controls).

I've also done some googling and looked on bob powell's site but can't find nuffin.

ResetClip resets the clipping region for the Graphics object to an infinitely large Rectangle, but the Graphics object cheerfully continues to use the provided ClipRectangle.


Recap: It sounds like you have a child control with a custom paint method. You want to paint the control in an area that is larger than the control's bounds itself. For instance if you place your control at (10, 10, 100, 100) you want to draw the area at (0, 10, 110, 100).

You can't exactly do that, the control's HDC that is passed to paint method is for that control's native window handle. It is clipped by the OS and AFAIK there is no way to draw outside of it with the HDC given to the paint method.

What you can do: One option is to override the parent window's create method and remove the window style WS_CLIPCHILDREN (0x02000000), then draw the child in the parent's paint method.

Another option is to just expand the area of the child window so that it encompasses the area you want to draw. If you also override the OnPaintBackground method of your control you can prevent the background paint from clearing the parent's rendering. This is problematic though since the parent will clip the area of the child and not refresh it. Thus you still need to remove the parent's WS_CLIPCHILDREN for it to work.

I'm sure there are other possibilities all of which are basically the same result, you can't do that.

Rectangle is a struct, not a class - it's passed as value so calling e.ClipRectangle.Inflate(100, 0); can't help even theoretically.

Next thing you have to know is that e.Graphics is related to hardware device context, so Windows won't let you expand painting area. Solution is to get device context of the parent window and then paint wherever you want to. This is how to do it:

static extern IntPtr GetDC(IntPtr hwnd);
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

IntPtr dcPtr = GetDC(this.ParentForm.Handle);
Graphics g = Graphics.FromHdc(dcPtr);

// your code here

// don't forget to release it
ReleaseDC(this.ParentForm.Handle, dcPtr);