繁体   English   中英

WPF:StackPanel与FirstChildFill?

[英]WPF: StackPanel with FirstChildFill?

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

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

但它也有很多xaml。 我真正想要的是这样的:

<StackPanel Fill="None|First|Last">
  <Button Content="1" />
  <Button Content="2" />
  <Button Content="3" />
</StackPanel>

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

您始终可以使用不同的对接规则编写自己的面板。 您可以使用标准的DockPanel实现(在框架源中可用 - 看起来并不复杂)并使用您喜欢的规则创建类似的东西。 您甚至可以创建一个派生自DockPanel并覆盖ArrangeOverride的类。

但就个人而言,我只会使用停靠面板,它完全符合您的要求,除非您不喜欢关于哪个成员填充的规则。

如果您插入/删除行,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);
    }
}

您可以在其中使用带有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中,则可以使用具有两行的Grid和第二行中的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>

WPF中没有这样的面板可以支持这种开箱即用的功能。 如果你想要这个特殊的行为,你可以创建自己的面板,但我不建议你这样做,因为它是非常自定义的并且不需要那么频繁(如果想要一个像MiddleChildFill这样的行为的面板怎么办?会创建那个案子也是你自己的小组?)。

通常这种布局是使用Grid实现的(正如您所提到的)。 是的,这是事实, Grid有一个非常详细的语法(你可以使用像一个助手简化它这个 ),但它给你最大的灵活性。 在一天结束时,这是最重要的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM