代码之家  ›  专栏  ›  技术社区  ›  GraemeF

如何将stackpanel的子元素隔开?

  •  162
  • GraemeF  · 技术社区  · 15 年前

    给定stackpanel:

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

    哪种最好的方法来隔开子元素,以便它们之间存在大小相等的间隙,即使子元素本身的大小不同?是否可以在不设置每个单独子级的属性的情况下完成此操作?

    10 回复  |  直到 7 年前
        1
  •  250
  •   Sergey Aldoukhov    15 年前

    使用页边距或填充,应用于容器内的作用域:

    <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>
    
        2
  •  78
  •   Elad Katz    13 年前

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

    这是将页边距设置为面板的几个子级(即使它们不是同一类型)的最简单、最快的方法。(即按钮、文本框、组合框等)

        3
  •  11
  •   angularsen Bcelik    7 年前

    我改进了 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>
    
        4
  •  6
  •   bradgonesurfing    9 年前

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

    <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

        5
  •  4
  •   Community kfsone    7 年前

    +1代表谢尔盖的回答。如果你想把它应用到所有的堆叠面板上,你可以这样做:

    <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 很幸运,它有一些解决办法。

        6
  •  3
  •   George Birbilis    12 年前

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

    <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属性设置为该外部样式资源(比如使用键“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-catastrophic-failure-when-a-style-tries-to-set-style-property#

        7
  •  2
  •   Jean Azzopardi    15 年前

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

        8
  •  2
  •   TeaDrivenDev    8 年前

    我的方法继承了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
  •  2
  •   Pedro Lamas    7 年前

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

    这些属性目前仅在Windows10 Fall Creators Update Insider SDK中可用,但应使其成为最终的位!

        10
  •  0
  •   Danil    11 年前

    有时需要设置填充,而不是空白以使项目之间的空间小于默认值