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

1

8

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.

Cyclograph answered 9/5, 2012 at 0:2 Comment(2)
Out of curiosity, what is the problem this solution is going to solve?Hittite
@roken: I want to know when the label is wider than its container so that I can add a tooltip to show the entire text of the label if, and only if, the entire text isn't visible. I would use the Label.AutoEllipsis property, but that doesn't work when AutoSize is true.Cyclograph
L
7

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.

Lindo answered 11/5, 2012 at 7:38 Comment(4)
This is a better way to find out if a control is clipped by any of its containers. It doesn't strictly answer my question, as this won't work if the control is clipped by a sibling, but it's still very helpful and educational (and I will use it unless a better method is found). Thank you! Yes, autosizing can be a pain. But it's very useful when you want containers to grow with their contents.Cyclograph
If you need to know about how siblings effect it, you can just search more of the control tree.Lindo
Yes, I'd need to check every control in every container all the way up to the form, while accounting for z-order amongst sibling controls. And if I wanted it to be really reliable, I'd have to look at other forms that might be overlapping my control... this is why it would be nice if a call already exists to do this. :)Cyclograph
Which is why you don't do it this way :) Using autosize just doesn't seem to be the right fit as far as I can see. But then again I'm not the one with all the information and the code to write :). Good luck!Lindo

© 2022 - 2024 — McMap. All rights reserved.