如何分隔StackPanel的子元素?

时间:2009-05-31 17:34:04

标签: wpf silverlight xaml stackpanel

给出StackPanel:

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

最好的方法是将子元素分开,以便它们之间有相同大小的间隙,即使子元素本身具有不同的大小?可以在不为每个孩子设置属性的情况下完成吗?

11 个答案:

答案 0 :(得分:257)

使用边距或填充,应用于容器中的范围:

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

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

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

答案 1 :(得分:80)

这里可以看到另一种不错的方法: 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>

这是最简单的&amp;将边距设置为面板的几个子节点的最快方法,即使它们的类型不同。 (即按钮,文本框,组合框等)

答案 2 :(得分:12)

我改进了Elad Katz' answer

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

Source code in gist

示例:

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

答案 3 :(得分:8)

你真正想要做的是包装所有子元素。在这种情况下,你应该使用一个物品控制,而不是诉诸于可怕的附属物,你最终会为你想要造型的每个物业赚一百万。

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

enter image description here

答案 4 :(得分:5)

+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这样的大多数无外观控件来说这不是问题,但对于文本框等,你可能偶然发现this problem,幸运的是有一些解决方法。

答案 5 :(得分:3)

根据谢尔盖的建议,您可以定义和重用整个样式(使用各种属性设置器,包括边距),而不仅仅是厚度对象:

<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立即以CATASTROPHIC FAILURE错误(HRESULT:0x8000FFFF(E_UNEXPECTED))关闭,如https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails-with-catastrophic-failure-when-a-style-tries-to-set-style-property#所述

答案 6 :(得分:3)

Grid.ColumnSpacingGrid.RowSpacingStackPanel.Spacing现在正在进行UWP预览,所有这些都可以更好地完成此处要求的内容。

这些属性目前仅适用于Windows 10 Fall Creators Update Insider SDK,但应该是最终位!

答案 7 :(得分:2)

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

答案 8 :(得分:2)

我的方法继承了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();
        }
    }
}

答案 9 :(得分:1)

通常,我这样使用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>

答案 10 :(得分:0)

有时您需要设置填充,而不是边距,以便在小于默认值的项目之间留出空间