I found a few other questions from people dealing with subclassing Panel in WPF and implementing their own layout work, and getting Infinity or PositiveInfinity for a dimension passed to MeasureOverride in the availableSize arg. The responses are generally, "It means you can take up as much room as you want: ignore it, add up the desired sizes of all your children and return that."
In my case I'm making a control that dynamically resizes to fill available space, so there is no intrinsic notion of desired size. It just wants to use the whole availableSize.
When I built out the ControlTemplate it ended up nested within a StackPanel, and it started getting Infinity for the available height, even though the control had no scrollbar. If I just capped it at some fixed number, it would just clip against the window. I tried returning ActualHeight, but that didn't work because it's cyclical: there's no ActualHeight before I've done a full layout pass. So that was always 0.0.
At first I didn't know it was the StackPanel handing down Infinity and dug through the reference source for a while to no avail, and finally figured it out by using VisualTreeHelper to run through the parents and look at their ActualHeight and the StackPanel was the deepest one with a non-zero height. I changed it to be a DockPanel since I only need two controls in it, so that works as well as a StackPanel. And behold, DockPanel doesn't pass Infinity for the available height.
But that just feels like a workaround; I'd like to understand in more depth the philosophy behind the layout and why one of the standard containers with no scrollbar would tell me I can have as much space as I want. What's the "right" response to that?
This:
I'm making a control that dynamically resizes to fill available space,
Is a bad combination with:
it ended up nested within a StackPanel
A control that "fills out space" should not be inside a stackpanel. What size do you think it should be?
Same for ScrollPanel of course.
Alright, having talked to other people offline too, here's the best of my understanding:
In the case where you want to do more sophisticated layout using a LayoutTransform or RenderTransform, thereby adding indirection between the control's measure / arrange pass and the actual pixel boundaries it appears within, the behavior of telling all stacked controls they can take up as much space as they want is reasonable because you're just trying to layout to a surface divorced from the actual clipped area on-screen.
It still feels like this falls under the category of "if you wrap a StackPanel in something scrollable..." but admittedly it's not clear what, in my suggested version, availableSize should be once you start messing with the RenderTransform for the StackPanel. (Though it's more fundamental than that; RenderTransform doesn't "play nice" with MeasureOverride by design because it's designed separate from the layout mechanism for performance... so it's still not clear this is a great argument.)
In any case, a way to get the behavior of a StackPanel where some selected item consumes the remainder not used by the other elements is to use a DockPanel, shove the fixed-size elements in StackPanels at Top or Bottom and the dynamically resizable one either on Top or Bottom or in the middle between two stacks.
I suppose if I needed multiple elements consuming available space in a proportioned way, that's what Grid is for.
But I have to say I still don't understand from a principled perspective why StackPanel passes Infinity down for its orientation direction to its children when calling MeasureOverride; I see no arguments for why you wouldn't pass the actual remaining unclaimed available size passed in by StackPanel's parent, and several arguments for why you would.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With