如何使StackPanel的子级向下填充最大空间?


356

我只想在左侧输入文字,在右侧输入帮助框。

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

如果取出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>

回答:

谢谢马克,用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>

修复了格式设置-它不喜欢直接从列表转到代码
Greg

1
您可以单独使GroupBox伸展吗?如果是这样,请开始一个接一个地添加父元素,直到找到哪个元素正在破坏布局。
Drew Noakes,2009年

RoBorg:很高兴知道,这让我感到困惑,谢谢
Edward Tanguay

1
谢谢。使用您的答案,我能够使用2个嵌套的DockPanels解决我非常相似的问题!
Yablargo

Answers:


344

听起来好像您想要StackPanel最终元素将所有剩余空间都用完的地方。但是为什么不使用DockPanel?装修中的其他元素DockPanelDockPanel.Dock="Top",然后你的帮助控制可以填补剩余空间。

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>

18
辉煌!我花了最后一个小时试图弄清楚如何让StackPanel做到这一点。从现在开始,我将首先在这里查看我的WPF(和其他)信息。
paxdiablo 2010年

7
我不敢相信我花了多少时间试图让StackPanels做我想做的事情。感谢分享!DockPanel是我一直想要的。
danglund 2012年


1
Windows应用商店应用没有停靠面板。
Teoman shipahi 2014年

现在,所有内容都与通用应用有关,通用应用还不支持DockPanel吗?
yonexbat '16

105

发生这种情况的原因是,堆叠面板会测量每个具有正无穷大的子元素作为对其沿其堆叠元素的轴的约束。子控件必须返回想要的大小(正无穷大不是从任一轴上的MeasureOverride的有效返回),因此它们将返回所有大小都适合的最小尺寸。他们无法知道他们真正需要填充多少空间。

如果您的视图不需要滚动功能,并且上面的答案不符合您的需求,我建议您实施自己的面板。您可能可以直接从StackPanel派生,然后您需要做的就是更改ArrangeOverride方法,以便将剩余空间分配到其子元素之间(为它们各分配相同的额外空间)。如果为元素提供了比所需更多的空间,它们应该可以很好地渲染,但是如果给它们的元素较少,则会开始看到毛刺。

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


+1,我会给您更多,但只允许1个,您的第一段指出了许多Microsoft页面无法完成的工作,即为什么无限可能会以高度/宽度出现,以及您不能依靠从MeasureOverride返回availableSize的事实。
艾丹(Aidan)2012年

网格内部的StackPanel可以轻松解决他相当普遍的需求。如有必要,可以将底部位放在ScrollViewer中。自2006年以来,我一直在做WPF,并且只需要做一次自定义面板。我认为鼓励额外的复杂性不是一个好主意。
克里斯·鲍德曼

@ChrisBordeman我不确定我是否了解网格内部的堆栈面板如何解决问题。想法是使堆栈面板中的一个或多个子元素伸展以填充可用空间。将堆栈面板放在网格中并不能做到这一点吗?
Caleb Vear

61

一种替代方法是使用具有一列和n行的网格。将所有行高度设置为Auto,将最底部的行高度设置为1*

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


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

18

您可以使用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中的表单(而不是)非常有用DockPanelStackPanel并且Grid可以非常轻松而优雅地解决拉伸问题。只需在GitHub上查看自述文件即可。

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

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

    <Label Content="Comment:"/>
    <TextBox/>
</st:AutoGrid>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.