Search code examples
c#wpfxamllayoutexpander

How to make an expander control hover over the next element?


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?


Solution

  • 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).