如何使扩展控件悬停在下一个元素上?

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

在下面举例说明的我的设置中,直到最近我才注意到当扩展器中列出的元素列表增长时(以至于它的长度超过了旁边面板中按钮的长度),它不会像直观预期的那样悬停在数据网格上。相反,它将它向下推,使整个 GUI 在垂直方向上显得跳跃。

<StackPanel>
  <StackPanel Orientation="Horizontal">
    <StackPanel>
      <Expander>...</Expander>
    </StackPanel>
    <StackPanel>
      <Button ... /><Button ... /><Button ... />
    </StackPanel>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <DataGrid ... />
  </StackPanel>
</StackPanel>

解决此问题的一种方法是将所有内容都放在网格中的同一个单元格中,最后添加扩展器。然而,在我看来,这在几个层面上都是不合适的。相反,我更愿意强制扩展器在 其他控件之上无接触地扩展。它应该会影响布局,但只会影响折叠状态下的尺寸。扩展应该不会影响布局。

如何告诉愚蠢的扩展器不要那么咄咄逼人?

为了便于参考,让我们对原始 XAML 中的 StackPanel 个元素进行编号:

<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 在水平方向时会将其高度设置为其 最高的 child,而在垂直方向时会将其高度设置为 其child人身高的总和

展开 Expander 控件时,会增加其高度,因此会增加其容器的高度 (#3)。这反过来可能会或可能不会增加 #3 的 parent 容器 (#2) 的高度,具体取决于扩展器的高度是否变得比包含按钮 (#4) 的堆栈面板更大。

为了达到您想要的效果,您可以使用问题和其他答案中已经讨论过的 Grid,也可以像这样使用 Canvas 元素:

<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>

此处使用的 canvas 允许扩展器控制 "escape" 容器的边界。要将扩展器控件置于其正下方元素上方的 "float"(本例中的 TextBlock),使用附加的 Panel.ZIndex 属性。我们还需要将 canvas 的宽度绑定到扩展器的宽度,因为 canvas 不会根据其 children.

调整自身大小

展开器折叠后的样子如下:

展开后的样子:

(请原谅可怕的颜色,它们只是为了让您看到控制边界在哪里)。

这是一个非常突出的问题post,当你寻找这类问题的答案时,我觉得应该提到 <popup> 在这种情况下可以很好地工作。

在扩展器的内容中放置一个 <popup>,您将通过更简单的 Xaml 布局实现相同类型的功能。

编辑:我已经探索了这个选项,但有一点需要注意...弹出窗口内置于其他 WINDOWS 之上!您需要将弹出窗口编程为在 window 失去焦点时关闭或稍微覆盖模板。这也可以很容易地用谷歌搜索。