我如何隔离StackPanel的子元素?

给定一个StackPanel:

<StackPanel> <TextBox Height="30">Apple</TextBox> <TextBox Height="80">Banana</TextBox> <TextBox Height="120">Cherry</TextBox> </StackPanel> 

尽pipe子元素本身大小不同,但是最好的办法是隔开子元素,使它们之间有相同的空隙。 可以在没有为每个孩子设置属性的情况下完成吗?

使用Margin或Padding,应用于容器内的范围:

 <StackPanel> <StackPanel.Resources> <Style TargetType="{x:Type TextBox}"> <Setter Property="Margin" Value="0,10,0,0"/> </Style> </StackPanel.Resources> <TextBox Text="Apple"/> <TextBox Text="Banana"/> <TextBox Text="Cherry"/> </StackPanel> 

编辑:如果您想重新使用两个容器之间的边距,可以将边距值转换为外部范围中的资源fe

 <Window.Resources> <Thickness x:Key="tbMargin">0,10,0,0</Thickness> </Window.Resources> 

然后在内部范围内引用此值

 <StackPanel.Resources> <Style TargetType="{x:Type TextBox}"> <Setter Property="Margin" Value="{StaticResource tbMargin}"/> </Style> </StackPanel.Resources> 

另一个不错的方法可以在这里看到: http : //blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between-项function于stackpanel.aspx

它显示了如何创build一个附加的行为,以便像这样的语法将工作:

 <StackPanel local:MarginSetter.Margin="5"> <TextBox Text="hello" /> <Button Content="hello" /> <Button Content="hello" /> </StackPanel> 

这是将Margin设置为面板的几个孩子的最简单和最快的方法,即使它们不是同一types。 (即button,文本框,combobox等)

我改进了Elad Katz的回答 。

  • 将LastItemMargin属性添加到MarginSetter以专门处理最后一个项目
  • 添加垂直和水平属性的间距附加属性,在垂直和水平列表中添加项目之间的间距,并消除列表末尾的任何尾部余量

源代码在要点 。

例:

 <StackPanel Orientation="Horizontal" foo:Spacing.Horizontal="5"> <Button>Button 1</Button> <Button>Button 2</Button> </StackPanel> <StackPanel Orientation="Vertical" foo:Spacing.Vertical="5"> <Button>Button 1</Button> <Button>Button 2</Button> </StackPanel> <!-- Same as vertical example above --> <StackPanel Orientation="Vertical" foo:MarginSetter.Margin="0 0 0 5" foo:MarginSetter.LastItemMargin="0"> <Button>Button 1</Button> <Button>Button 2</Button> </StackPanel> 

你真正想要做的是包装所有的子元素。 在这种情况下,你应该使用物品控制,而不是诉诸可怕的附加属性,你将最终拥有一个你想要风格的每一个属性的百万。

 <ItemsControl> <!-- target the wrapper parent of the child with a style --> <ItemsControl.ItemContainerStyle> <Style TargetType="Control"> <Setter Property="Margin" Value="0 0 5 0"></Setter> </Style> </ItemsControl.ItemContainerStyle> <!-- use a stack panel as the main container --> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <!-- put in your children --> <ItemsControl.Items> <Label>Auto Zoom Reset?</Label> <CheckBox x:Name="AutoResetZoom"/> <Button x:Name="ProceedButton" Click="ProceedButton_OnClick">Next</Button> <ComboBox SelectedItem="{Binding LogLevel }" ItemsSource="{Binding LogLevels}" /> </ItemsControl.Items> </ItemsControl> 

在这里输入图像说明

谢尔盖答案+1。 如果你想把它应用到你所有的StackPanel上,你可以这样做:

 <Style TargetType="{x:Type StackPanel}"> <Style.Resources> <Style TargetType="{x:Type TextBox}"> <Setter Property="Margin" Value="{StaticResource tbMargin}"/> </Style> </Style.Resources> </Style> 

但要小心:如果在App.xaml(或合并到Application.Resources中的另一个字典)中定义了这样的样式,则可以覆盖该控件的默认样式。 对于像stackpanel大多不寻常的控制它不是一个问题,但对于文本框等你可能偶然发现这个问题 ,幸运的是有一些解决方法。

根据Sergey的build议,您可以定义和重用整个样式(使用各种属性设置器,包括Margin),而不仅仅是一个Thickness对象:

 <Style x:Key="MyStyle" TargetType="SomeItemType"> <Setter Property="Margin" Value="0,5,0,5" /> ... </Style> 

  <StackPanel> <StackPanel.Resources> <Style TargetType="SomeItemType" BasedOn="{StaticResource MyStyle}" /> </StackPanel.Resources> ... </StackPanel> 

请注意,这里的技巧是使用隐式样式的样式inheritance,从某些外部样式(可能从外部XAML文件合并)资源字典中inheritance样式inheritance。

边注:

起初,我天真地尝试使用隐式样式将控件的Style属性设置为该外部样式资源(用“MyStyle”键定义):

 <StackPanel> <StackPanel.Resources> <Style TargetType="SomeItemType"> <Setter Property="Style" Value={StaticResource MyStyle}" /> </Style> </StackPanel.Resources> </StackPanel> 

这导致Visual Studio 2010立即closures与灾难故障错误(HRESULT:0x8000FFFF(E_UNEXPECTED)),在https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails -with灾难性故障影响的时候,一个风格,尝试到组样式属性#

UniformGrid可能在Silverlight中不可用,但有人从WPF移植它。 http://www.jeff.wilcox.name/2009/01/uniform-grid/

有时您需要设置“填充”,而不是“边距”以使项目之间的间距小于默认值

我的方法inheritanceStackPanel。

用法:

 <Controls:ItemSpacer Grid.Row="2" Orientation="Horizontal" Height="30" CellPadding="15,0"> <Label>Test 1</Label> <Label>Test 2</Label> <Label>Test 3</Label> </Controls:ItemSpacer> 

所需要的只是以下的短课:

 using System.Windows; using System.Windows.Controls; using System; namespace Controls { public class ItemSpacer : StackPanel { public static DependencyProperty CellPaddingProperty = DependencyProperty.Register("CellPadding", typeof(Thickness), typeof(ItemSpacer), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnCellPaddingChanged)); public Thickness CellPadding { get { return (Thickness)GetValue(CellPaddingProperty); } set { SetValue(CellPaddingProperty, value); } } private static void OnCellPaddingChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { ((ItemSpacer)Object).SetPadding(); } private void SetPadding() { foreach (UIElement Element in Children) { (Element as FrameworkElement).Margin = this.CellPadding; } } public ItemSpacer() { this.LayoutUpdated += PART_Host_LayoutUpdated; } private void PART_Host_LayoutUpdated(object sender, System.EventArgs e) { this.SetPadding(); } } } 

Grid.ColumnSpacing , Grid.RowSpacing , StackPanel.Spacing现在在UWP预览,所有将允许更好地实现这里所要求的。

这些属性目前仅在Windows 10 Fall Creators Update Insider SDK中可用,但应该使其达到最后的位!