给定一个StackPanel:
<StackPanel>
<TextBox Height="30">Apple</TextBox>
<TextBox Height="80">Banana</TextBox>
<TextBox Height="120">Cherry</TextBox>
</StackPanel>
在子元素本身大小不同的情况下,怎样才能使它们之间的间隔大小相等呢?在不为每个单独的子节点设置属性的情况下可以做到这一点吗?
给定一个StackPanel:
<StackPanel>
<TextBox Height="30">Apple</TextBox>
<TextBox Height="80">Banana</TextBox>
<TextBox Height="120">Cherry</TextBox>
</StackPanel>
在子元素本身大小不同的情况下,怎样才能使它们之间的间隔大小相等呢?在不为每个单独的子节点设置属性的情况下可以做到这一点吗?
当前回答
我改进了埃拉德·卡茨的回答。
为MarginSetter添加LastItemMargin属性以专门处理最后一项 “添加间距”附加属性具有“垂直”和“水平”属性,用于在垂直和水平列表中的项之间添加间距,并消除列表末尾的任何尾距
源代码在主旨。
例子:
<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>
我改进了埃拉德·卡茨的回答。
为MarginSetter添加LastItemMargin属性以专门处理最后一项 “添加间距”附加属性具有“垂直”和“水平”属性,用于在垂直和水平列表中的项之间添加间距,并消除列表末尾的任何尾距
源代码在主旨。
例子:
<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>
我的方法继承了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();
}
}
}
这里可以看到另一个很好的方法: http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between-items-in-stackpanel.aspx 链接断了->这是这个链接的webbarchive。
它展示了如何创建一个附加的行为,这样的语法就可以工作:
<StackPanel local:MarginSetter.Margin="5">
<TextBox Text="hello" />
<Button Content="hello" />
<Button Content="hello" />
</StackPanel>
这是最简单和最快的方法来设置边缘的几个子面板,即使他们不属于同一类型。(即按钮,文本框,组合框等)
Sergey的答案是+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中的另一个字典)中定义了这样的样式,它会覆盖控件的默认样式。对于大多数无外观的控件,如堆栈面板,这不是一个问题,但对于文本框等,你可能会偶然发现这个问题,幸运的是有一些变通办法。