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-这是你的选择,我只是在分享我的经验:)