Reputation: 39250
In my setup exemplified below, I didn't notice until recently that when the list of elements listed in the expander grows (so that the length of it exceeds the length of the buttons in the panel next to it), it doesn't hover over the data grid, as intuitively expected. Instead, it pushes it down which makes the whole GUI to appear jumpy vertically.
<StackPanel>
<StackPanel Orientation="Horizontal">
<StackPanel>
<Expander>...</Expander>
</StackPanel>
<StackPanel>
<Button ... /><Button ... /><Button ... />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal">
<DataGrid ... />
</StackPanel>
</StackPanel>
One way to fix this is to put everything in the same cell in a grid and add the expander last. However, that seems to me inappropriate on several levels. Instead, I'd prefer to force expander to expand touchlessly above the other controls. It should affect the layout but only its size from the folded state. The expansion should not affect the layout at all.
How can I tell the stupid expander not to be so pushy?
Upvotes: 1
Views: 5937
Reputation: 23
This is such a prominent post when you look for answers for this kind of problem, I feel it should be mentioned that a <popup>
can work very well in this situation.
Place a <popup>
inside the content of the expander and you will achieve the same sort of functionality with a much simpler Xaml layout.
Edit: I've explored this option and there's a caveat... Popups are built int to go above OTHER WINDOWS! You'll need to either program the popup to close when the window loses focus or override the template a bit. This can also be easily googled.
Upvotes: 1
Reputation: 5421
For reference, let's number the StackPanel
elements from your original XAML:
<StackPanel #1>
<StackPanel #2 Orientation="Horizontal">
<StackPanel #3>
<Expander>...</Expander>
</StackPanel>
<StackPanel #4>
<Button ... /><Button ... /><Button ... />
</StackPanel>
</StackPanel>
<StackPanel #5 Orientation="Horizontal">
<DataGrid ... />
</StackPanel>
</StackPanel>
A StackPanel
when oriented horizontally will set its height to that of its tallest child, and when oriented vertically will set its height to the sum of all of its children's heights.
When you expand the Expander
control, you increase its height, and therefore you increase the height of its container (#3). This in turn may or may not increase the height of #3's parent container (#2) depending on whether the expander becomes larger in height than the stack panel containing the buttons (#4).
To achieve the effect you seem to be after, you can either use a Grid
as already discussed in the question and other answer, or you can use a Canvas
element like so:
<Window x:Class="..."
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<StackPanel Orientation="Horizontal" Panel.ZIndex="1">
<Canvas Width="{Binding ActualWidth, ElementName=Expander}">
<Expander x:Name="Expander" Header="Header" Background="Yellow">
<StackPanel Background="Aqua">
<TextBlock Text="Some text" />
<TextBlock Text="Some text" />
<TextBlock Text="Some text" />
<TextBlock Text="Some text" />
<TextBlock Text="Some text" />
<TextBlock Text="Some text" />
</StackPanel>
</Expander>
</Canvas>
<StackPanel>
<Button Content="Button1" />
<Button Content="Button2" />
<Button Content="Button3" />
</StackPanel>
</StackPanel>
<TextBlock Text="Some more text" Background="LimeGreen" />
</StackPanel>
</Window>
The canvas as used here allows the expander control to "escape" the boundaries of the container. To get the expander control to "float" above the element directly underneath it (the TextBlock
in this example), the Panel.ZIndex
attached property is used. We also need to bind the width of the canvas to the width of the expander as the canvas will not size itself based on its children.
Here's how it looks when the expander is collapsed:
And how it looks when it is expanded:
(Forgive the horrible colours, they are just so you can see where the control boundaries are).
Upvotes: 8