我想要一种逻辑和简单的方法来生成一个布局,其中一个控件集要填充,其余的要停靠。我可以用:
<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那样反转项目的情况下实现这一目标,而不是像Grid一样使用固定数量的行和附加属性?
答案 0 :(得分:3)
您始终可以使用不同的停靠规则编写自己的面板。您可以使用标准的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);
}
}
答案 1 :(得分:1)
您可以在其中使用带有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>
答案 2 :(得分:0)
WPF中没有这样的面板可以支持这种开箱即用的功能。如果你想要这个特殊的行为,你可以创建自己的面板,但我不建议你这样做,因为它是非常自定义的并且不需要那么频繁(如果想要一个像MiddleChildFill这样的行为的面板怎么办?会创建那个案子也是你自己的小组?)。
通常使用Grid
(如您所述)实现此类布局。是的,Grid
具有非常冗长的语法(您可以使用this之类的帮助器来简化它),但它为您提供了最大的灵活性。在一天结束时,这才重要。