如何让 StackPanel 的孩子向下填充最大空间?

Posted

技术标签:

【中文标题】如何让 StackPanel 的孩子向下填充最大空间?【英文标题】:How to get StackPanel's children to fill maximum space downward? 【发布时间】:2010-10-08 19:39:52 【问题描述】:

我只想在左侧显示流畅的文本,在右侧显示帮助框。

帮助框应该一直延伸到底部。

如果你去掉下面的外部StackPanel,效果会很好。

但出于布局原因(我正在动态插入 UserControls),我需要包装 StackPanel

如何让GroupBox 向下延伸到StackPanel 的底部,如您所见,我已经尝试过了:

VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" Height="Auto"

XAML:

<Window x:Class="TestDynamic033.Test3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test3" Height="300" Width="600">
    <StackPanel 
        VerticalAlignment="Stretch" 
        Height="Auto">

        <DockPanel 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" 
            Height="Auto" 
            Margin="10">

            <GroupBox 
                DockPanel.Dock="Right" 
                Header="Help" 
                Width="100" 
                Background="Beige" 
                VerticalAlignment="Stretch" 
                VerticalContentAlignment="Stretch" 
                Height="Auto">
                <TextBlock Text="This is the help that is available on the news screen." TextWrapping="Wrap" />
            </GroupBox>

            <StackPanel DockPanel.Dock="Left" Margin="10" Width="Auto" HorizontalAlignment="Stretch">
                <TextBlock Text="Here is the news that should wrap around." TextWrapping="Wrap"/>
            </StackPanel>

        </DockPanel>
    </StackPanel>
</Window>

答案:

感谢 Mark,使用 DockPanel 而不是 StackPanel 清除了它。总的来说,我发现自己现在越来越多地使用 DockPanel 进行 WPF 布局,这是固定的 XAML:

<Window x:Class="TestDynamic033.Test3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test3" Height="300" Width="600" MinWidth="500" MinHeight="200">
    <DockPanel 
        VerticalAlignment="Stretch" 
        Height="Auto">

        <DockPanel 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" 
            Height="Auto" 
            MinWidth="400"
            Margin="10">

            <GroupBox 
                DockPanel.Dock="Right" 
                Header="Help" 
                Width="100" 
                VerticalAlignment="Stretch" 
                VerticalContentAlignment="Stretch" 
                Height="Auto">
                <Border CornerRadius="3" Background="Beige">
                    <TextBlock Text="This is the help that is available on the news screen." TextWrapping="Wrap" 

                Padding="5"/>
                </Border>
            </GroupBox>

            <StackPanel DockPanel.Dock="Left" Margin="10" Width="Auto" HorizontalAlignment="Stretch">
                <TextBlock Text="Here is the news that should wrap around." TextWrapping="Wrap"/>
            </StackPanel>

        </DockPanel>
    </DockPanel>
</Window>

【问题讨论】:

修复了格式 - 它不喜欢直接从列表转到代码 你可以让 GroupBox 自行拉伸吗?如果是这样,开始一个一个地添加你的父元素,直到你找出哪个破坏了布局。 RoBorg:很高兴知道,这让我很困惑,谢谢 谢谢。使用您的答案,我能够使用 2 个嵌套的 DockPanel 来解决我非常相似的问题! 【参考方案1】:

您可以使用SpicyTaco.AutoGrid - StackPanel 的修改版本:

<st:StackPanel Orientation="Horizontal" MarginBetweenChildren="10" Margin="10">
   <Button Content="Info" HorizontalAlignment="Left" st:StackPanel.Fill="Fill"/>
   <Button Content="Cancel"/>
   <Button Content="Save"/>
</st:StackPanel>

第一个按钮将被填充。

你可以通过 NuGet 安装它:

Install-Package SpicyTaco.AutoGrid

我建议看看SpicyTaco.AutoGrid。它对于 WPF 中的表单而不是 DockPanelStackPanelGrid 非常有用,并且非常轻松优雅地解决了拉伸问题。只需查看 GitHub 上的自述文件。

<st:AutoGrid Columns="160,*" ChildMargin="3">
    <Label Content="Name:"/>
    <TextBox/>

    <Label Content="E-Mail:"/>
    <TextBox/>

    <Label Content="Comment:"/>
    <TextBox/>
</st:AutoGrid>

【讨论】:

这个应该在最上面,很有用,非常感谢! 别忘了加上 xmlns:st="schemas.spicytaco.io"【参考方案2】:

听起来你想要一个StackPanel,其中最后一个元素用完所有剩余空间。但为什么不使用DockPanel?用DockPanel.Dock="Top" 装饰DockPanel 中的其他元素,然后您的帮助控件可以填充剩余空间。

XAML:

<DockPanel Width="200" Height="200" Background="PowderBlue">
    <TextBlock DockPanel.Dock="Top">Something</TextBlock>
    <TextBlock DockPanel.Dock="Top">Something else</TextBlock>
    <DockPanel
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" 
        Height="Auto" 
        Margin="10">

      <GroupBox 
        DockPanel.Dock="Right" 
        Header="Help" 
        Width="100" 
        Background="Beige" 
        VerticalAlignment="Stretch" 
        VerticalContentAlignment="Stretch" 
        Height="Auto">
        <TextBlock Text="This is the help that is available on the news screen." 
                   TextWrapping="Wrap" />
     </GroupBox>

      <StackPanel DockPanel.Dock="Left" Margin="10" 
           Width="Auto" HorizontalAlignment="Stretch">
          <TextBlock Text="Here is the news that should wrap around." 
                     TextWrapping="Wrap"/>
      </StackPanel>
    </DockPanel>
</DockPanel>

如果您在没有DockPanel 可用的平台上(例如 WindowsStore),您可以使用网格创建相同的效果。这是上面使用网格完成的示例:

<Grid Width="200" Height="200" Background="PowderBlue">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0">
        <TextBlock>Something</TextBlock>
        <TextBlock>Something else</TextBlock>
    </StackPanel>
    <Grid Height="Auto" Grid.Row="1" Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
        <GroupBox
            Width="100"
            Height="Auto"
            Grid.Column="1"
            Background="Beige"
            Header="Help">
            <TextBlock Text="This is the help that is available on the news screen." 
              TextWrapping="Wrap"/>
        </GroupBox>
        <StackPanel Width="Auto" Margin="10" DockPanel.Dock="Left">
            <TextBlock Text="Here is the news that should wrap around." 
              TextWrapping="Wrap"/>
        </StackPanel>
    </Grid>
</Grid>

【讨论】:

太棒了!我花了最后一个小时试图弄清楚如何让 StackPanel 做到这一点。从现在开始,我将首先在此处查找我的 WPF(和其他)信息。 我无法相信我花了多少时间试图让 StackPanels 做我想做的事。感谢分享! DockPanel 是我一直想要的。 似乎没有平板电脑的停靠面板。 telerik.com/forums/following-blog-post-and-comparison 没有适用于 Windows 应用商店应用的停靠面板。 现在都是通用应用,通用应用还不支持 DockPanel?【参考方案3】:

发生这种情况的原因是因为堆栈面板测量每个子元素,正无穷大作为它正在堆叠元素的轴的约束。子控件必须返回它们想要的大小(正无穷大不是来自任一轴的MeasureOverride 的有效返回),因此它们返回适合所有内容的最小尺寸。他们无法知道自己真正需要填满多少空间。

如果您的视图不需要具有滚动功能并且上面的答案不适合您的需求,我建议您实现自己的面板。您可能可以直接从 StackPanel 派生,然后您需要做的就是更改 ArrangeOverride 方法,以便它在其子元素之间划分剩余空间(给它们每个相同数量的额外空间)。如果给元素的空间比他们想要的多,它们应该可以很好地渲染,但如果你给它们的空间少,你就会开始看到故障。

如果您希望能够滚动整个内容,那么恐怕事情会变得更加困难,因为 ScrollViewer 为您提供了无限的工作空间,这将使您处于与最初是子元素。在这种情况下,您可能希望在新面板上创建一个新属性,让您指定视口大小,您应该能够将其绑定到 ScrollViewer 的大小。理想情况下,您应该实现 IScrollInfo,但如果您要正确实现所有这些,事情就会变得复杂。

【讨论】:

+1,我会给你更多,但只允许 1,你的第一段指出了许多 Microsoft 页面未能做到的事情,即为什么无穷大可以作为高度/宽度出现以及事实您不能依赖从 MeasureOverride 返回 availableSize。 Grid 中的 StackPanel 轻松解决了他相当普遍的需求。如有必要,可以将底部位放在 ScrollViewer 中。自 2006 年以来,我一直在做 WPF,并且只需要做一次自定义面板。我认为鼓励额外的复杂性不是一个好主意。 @ChrisBordeman 我不确定我是否理解网格内的堆栈面板如何解决问题。这个想法是让堆栈面板中的一个或多个子元素伸展以填充可用空间。将堆栈面板放在网格内并不能做到这一点吗?【参考方案4】:

另一种方法是使用一列和 n 行的 Grid。将所有行高设置为Auto,将最底部的行高设置为1*

我更喜欢这种方法,因为我发现网格比 DockPanel、StackPanel 和 WrapPanel 具有更好的布局性能。但是,除非您在 ItemTemplate 中使用它们(对大量项目执行布局),否则您可能永远不会注意到。

【讨论】:

对我来说是最好的解决方案。有了这个,就可以定义一个以上的增长行

以上是关于如何让 StackPanel 的孩子向下填充最大空间?的主要内容,如果未能解决你的问题,请参考以下文章

WPF:如何使控件在 StackPanel 中拉伸?

有两个孩子的父 div。即使没有显示另一个孩子,也总是让一个孩子填充父母?

在 StackPanel 上填充?

如何让 ScrollViewer 在 StackPanel 中工作?

如何将列最大高度限制为屏幕高度?即让孩子“match_parent”大小

WPF 如何让 Viewbox 从 StackPanel 中了解其可用空间