给定一个StackPanel:

<StackPanel>
  <TextBox Height="30">Apple</TextBox>
  <TextBox Height="80">Banana</TextBox>
  <TextBox Height="120">Cherry</TextBox>
</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();
        }
    }
}

其他回答

通常,我使用Grid而不是这样的StackPanel:

水平情况

<Grid>
 <Grid.ColumnDefinitions>
    <ColumnDefinition Width="auto"/>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition  Width="auto"/>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition  Width="auto"/>
 </Grid.ColumnDefinitions>
 <TextBox Height="30" Grid.Column="0">Apple</TextBox>
 <TextBox Height="80" Grid.Column="2">Banana</TextBox>
 <TextBox Height="120" Grid.Column="4">Cherry</TextBox>
</Grid>

垂直的情况下

<Grid>
     <Grid.ColumnDefinitions>
        <RowDefinition Width="auto"/>
        <RowDefinition Width="*"/>
        <RowDefinition  Width="auto"/>
        <RowDefinition Width="*"/>
        <RowDefinition  Width="auto"/>
     </Grid.ColumnDefinitions>
     <TextBox Height="30" Grid.Row="0">Apple</TextBox>
     <TextBox Height="80" Grid.Row="2">Banana</TextBox>
     <TextBox Height="120" Grid.Row="4">Cherry</TextBox>
</Grid>

您真正需要做的是包装所有子元素。在这种情况下,你应该使用一个项目控件,而不是诉诸于可怕的附加属性,你最终会有一百万个你想要样式的每个属性。

<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>

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();
        }
    }
}

这里可以看到另一个很好的方法: 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>

这是最简单和最快的方法来设置边缘的几个子面板,即使他们不属于同一类型。(即按钮,文本框,组合框等)