如何间隔 StackPanel 的子元素?
-
06-09-2019 - |
题
给定一个 StackPanel:
<StackPanel>
<TextBox Height="30">Apple</TextBox>
<TextBox Height="80">Banana</TextBox>
<TextBox Height="120">Cherry</TextBox>
</StackPanel>
即使子元素本身大小不同,间隔子元素以使它们之间的间隙大小相等的最佳方法是什么?是否可以在不为每个单独的子项设置属性的情况下完成此操作?
解决方案
使用保证金或填充,在容器内施加到范围:
<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>
编辑:如果你想重新使用两个容器之间的余量,可以将余量值转换为资源在外部范围,f.e
<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-items-in-stackpanel.aspx
它展示了如何创建附加行为,以便像这样的语法可以工作:
<StackPanel local:MarginSetter.Margin="5">
<TextBox Text="hello" />
<Button Content="hello" />
<Button Content="hello" />
</StackPanel>
这是为面板的多个子项设置边距的最简单、最快的方法,即使它们不是同一类型。(IE。按钮、文本框、组合框等)
我改进了 埃拉德·卡茨的回答.
- 在MarginSetter中添加LastItemMargin属性来专门处理最后一项
- 添加具有 Vertical 和 Horizontal 属性的 Spacing 附加属性,可添加垂直和水平列表中的项目之间的间距,并消除列表末尾的任何尾部边距
例子:
<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对谢尔盖的回答。如果你想要的是适用于所有StackPanels你可以这样做:
<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 的建议,您可以定义和重用整个 Style(具有各种属性设置器,包括 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>
请注意,这里的技巧是对隐式样式使用样式继承,从某些外部(可能从外部 XAML 文件合并)资源字典中的样式继承。
边注:
起初,我天真地尝试使用隐式样式将控件的 Style 属性设置为外部 Style 资源(例如使用“MyStyle”键定义):
<StackPanel>
<StackPanel.Resources>
<Style TargetType="SomeItemType">
<Setter Property="Style" Value={StaticResource MyStyle}" />
</Style>
</StackPanel.Resources>
</StackPanel>
这导致 Visual Studio 2010 立即关闭并出现灾难性故障错误(HRESULT:0x8000FFFF (E_UNEXPECTED)),如所述 https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails-with-catastropic-failure-when-a-style-tries-to-set-style-property#
Grid.ColumnSpacing 一>, Grid.RowSpacing 一>, StackPanel.Spacing 一>现在对UWP预览,都将有助于更好地在这里要求acomplish什么。
这些属性目前仅可在Windows 10秋季创作者更新内幕SDK,而应使它的最后位!
在UniformGrid可能无法在Silverlight中可用,但有人已经从WPF移植它。 http://www.jeff.wilcox.name/2009/01/uniform -grid /
我的方法继承的StackPanel。
用法:
<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();
}
}
}
有时你需要设置填充,没有保证金做项目比默认小之间的空间