Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF:带FirstChildFill的StackPanel?_C#_Wpf_Layout_Fill - Fatal编程技术网

C# WPF:带FirstChildFill的StackPanel?

C# WPF:带FirstChildFill的StackPanel?,c#,wpf,layout,fill,C#,Wpf,Layout,Fill,我想要一个逻辑和简单的方法来生成一个布局,其中一个控件集要填充,其余的控件集要停靠。我可以使用: <DockPanel LastChildFill="True"> <Button Content="3" DockPanel.Dock="Bottom" /> <Button Content="2" DockPanel.Dock="Bottom" /> <Button Content="1" /> </DockPanel>

我想要一个逻辑和简单的方法来生成一个布局,其中一个控件集要填充,其余的控件集要停靠。我可以使用:

<DockPanel LastChildFill="True">
  <Button Content="3" DockPanel.Dock="Bottom" />
  <Button Content="2" DockPanel.Dock="Bottom" />
  <Button Content="1" />
</DockPanel>

但使用起来不是很直观。我也可以这样做:

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Button Content="1" Grid.Row="0" />
  <Button Content="2" Grid.Row="1" />
  <Button Content="3" Grid.Row="2" />
</Grid>
<StackPanel Fill="None|First|Last">
  <Button Content="1" />
  <Button Content="2" />
  <Button Content="3" />
</StackPanel>

但它也相当多的xaml。我真正想要的是这样的东西:

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Button Content="1" Grid.Row="0" />
  <Button Content="2" Grid.Row="1" />
  <Button Content="3" Grid.Row="2" />
</Grid>
<StackPanel Fill="None|First|Last">
  <Button Content="1" />
  <Button Content="2" />
  <Button Content="3" />
</StackPanel>


如何在不必像DockPanel那样反转项目,也不必像Grid那样使用固定数量的行和附加属性的情况下实现这一点?

您始终可以使用不同的固定规则编写自己的面板。您可以使用标准的DockPanel实现(可在框架源代码中找到,看起来并不复杂),并使用您喜欢的规则创建类似的内容。您甚至可以创建一个派生自DockPanel和重写ArrangeOverride的类

但就我个人而言,我只会使用dock面板,它完全符合您的要求,只是您不喜欢它关于哪个成员可以填充的规则

如果您插入/删除行,IME网格会有一个可怕的维护问题,因为您会发现自己无休止地调整行号—DockPanel在这方面要容易得多

更新:

在这里,我已经拒绝了你自己做这件事的乐趣-这只是框架源代码的缩减/反转版本:

public class BottomDockingPanel : DockPanel
{
    protected override Size ArrangeOverride(Size arrangeSize)
    {
        UIElementCollection children = InternalChildren;
        int totalChildrenCount = children.Count;

        double accumulatedBottom = 0;

        for (int i = totalChildrenCount-1; i >=0 ; --i)
        {
            UIElement child = children[i];
            if (child == null) { continue; }

            Size childDesiredSize = child.DesiredSize;
            Rect rcChild = new Rect(
                0,
                0,
                Math.Max(0.0, arrangeSize.Width - (0 + (double)0)),
                Math.Max(0.0, arrangeSize.Height - (0 + accumulatedBottom)));

            if (i > 0)
            {
                accumulatedBottom += childDesiredSize.Height;
                rcChild.Y = Math.Max(0.0, arrangeSize.Height - accumulatedBottom);
                rcChild.Height = childDesiredSize.Height;
            }

            child.Arrange(rcChild);
        }
        return (arrangeSize);
    }
}

WPF中没有支持这种开箱即用的面板。如果您想要这种特殊的行为,您可以创建自己的面板,但我不建议您这样做,因为它是非常定制的,不需要经常使用(如果您想要一个具有类似MiddleChildFill行为的面板,您也会为这种情况创建自己的面板吗?)


通常,这种布局是使用
网格
(如您所述)实现的。是的,
Grid
确实有一个非常详细的语法(您可以使用类似于helper的工具来简化它),但是它给了您最大的灵活性。在一天结束时,这才是最重要的。

你可以使用一个里面有StackPanel的DockPanel。“主”内容将显示在最后,而不是第一个,但在XAML中,至少底部内容将按逻辑顺序显示。如果你想让填写的内容排在最后,这将是最简单的方法

<DockPanel LastChildFill="True">
  <StackPanel DockPanel.Dock="Bottom">
    <Button Content="Bottom 1" />
    <Button Content="Bottom 2" />
    <Button Content="Bottom 3" />
  </StackPanel>
  <Button Content="Main" />
</DockPanel>

或者,如果您希望所有内容(包括填充内容)都以在屏幕上显示的相同顺序显示在XAML中,则可以使用一个包含两行的网格,在第二行使用StackPanel。正如您所指出的,网格需要相当多的XAML,但是嵌套的StackPanel将使您不必为每个新项添加RowDefinition和Grid.Row

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Button Grid.Row="0" Content="Main" />
  <StackPanel Grid.Row="1">
    <Button Content="Bottom 1" />
    <Button Content="Bottom 2" />
    <Button Content="Bottom 3" />
  </StackPanel>
</Grid>


我的具体案例的问题是,我希望在ItemsContainer上使用模板生成此布局,并且我假设无法将itemspresenter拆分为“Main”和“rest”-可枚举。如果可能的话,我可以这样做……您可以始终让ViewModel公开两个属性:一个用于第一个子项(您希望填充空间),另一个用于其余项。然后第一个控件可以使用ContentControl,其余的控件可以使用ItemsControl。不完全优雅,但比编写自己的面板要简单一些。我经常准确地使用这种布局模型。我认为,一个带有填充最后一个或第一个孩子选项的StackPanel非常有用。@Andreas Zita-这是你的选择,我只是在分享我的经验:)