Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you get the size of the visible area of a clipped control?

Is there a way to get the size of the visible portion of a clipped control in WinForms?

A very simple example: place a control on a form and make the form width smaller than the control width. How do you get the width of the visible area of the control? In this case you can use the form's ClientSize, but it's not always that simple.

A more complex (and real) example: I have a label with AutoSize set to true, and it can to grow beyond the width of its containing control, causing it to be clipped. When this happens I need to know. It's not as simple as comparing the width of the label with the width of its container, since the container may also have AutoSize = true and also be clipped.

Currently my approach is to walk up the container tree until I find a container that has AutoSize = false, and get its width. I also have to take the padding of each container into account. But this only considers a control being clipped by its container, or its container's container, etc. It wouldn't work if the control in question, or any of the containers, are being clipped by a sibling control with a higher Z-order. And I suspect there are other ways to easily break this approach.

Changing the label AutoSize to false isn't an option. The label is on a UserControl which is set to AutoSize so that when the label grows, the UserControl grows with it. Getting this to work without using AutoSize is painful.

Things I've tried using, unsuccessfully:

Control.ClientSize, Control.ClientRectangle, Control.PreferredSize, Control.CreateGraphics().VisibleClipBounds.

I've played with the Graphics class a little but I'm in over my head there. Graphics.VisibleClipBounds sounded promising but always seems to return the same as the other size properties mentioned.

This pertains specifically to WinForms. I would be be happy with a p/invoke solution if that's all there is.

I did do an exhaustive search before posting. None of the similar questions are helpful.

like image 859
Igby Largeman Avatar asked May 09 '12 00:05

Igby Largeman


1 Answers

You can use Control.ClientRectangle for this. What you need to do is to get the screen bounds of each control while walking up the tree, and compute the intersection.

it will be something like this:

Control c = myControl;
var rect = c.RectangleToScreen(c.ClientRectangle);
while (c != null) {
    rect = Rectangle.Intersect(rect, c.RectangleToScreen(c.ClientRectangle));
    c = c.Parent;
}
rect = myControl.RectangleToClient(rect);

Now that should work for you, but to solve your problem of deciding when to draw ellipses, I recommend introducing better control sizing instead. It is generally better if each control is sizing appropriately so that all the information it requires is it's own size to decide how to draw it's contents.

The problem you describe is typical of auto size scenarios. You want it to size automatically, but also be constrained when containers are too small. I try to avoid auto size when possible and instead use the Dock property and custom layout login by overriding OnSizeChanged. This may or may not work out for what you need though.

like image 146
Phil Martin Avatar answered Oct 02 '22 18:10

Phil Martin