【问题标题】:What is the easy way to set spacing between items in StackPanel?在 StackPanel 中设置项目间距的简单方法是什么?
【发布时间】:2011-03-14 23:54:35
【问题描述】:

有没有一种简单的方法可以在 StackPanel 内的项目之间设置默认空间,这样我就不必为每个项目设置 Margin 属性?

【问题讨论】:

  • 我想说 Margin 是最简单的方法......它们通常是同一类型的项目吗?您可以使用隐式样式为每个项目设置 Margin...
  • 也许我可以使用样式为某些基本类型设置边距?以“控制”为例
  • 另请参阅此处接受的答案:stackoverflow.com/questions/932510/…

标签: c# wpf xaml stackpanel


【解决方案1】:

我用的是透明分隔符,效果很好:

<Separator Opacity="0" Height="20"/>

您当然可以使用边距,但是如果您想更改边距,则必须更新所有元素。

分隔符甚至可以在静态资源中设置样式。

附加属性也可以,但我认为这有点过头了。

【讨论】:

  • @Microsoft,太糟糕了,UWP 不支持这... :'(
  • 这个怎么用?我是否必须在每个子元素之后手动添加 Seperator 元素?我看不出这比直接为每个子项设置 Margin 属性更好。我错过了什么吗?
【解决方案2】:

如果所有控件都相同,则按照 IanR 的建议执行并实现一个样式来捕获该控件。如果不是,则无法为基类创建默认样式,因为它不起作用。

此类情况的最佳方法是使用一个非常巧妙的技巧 - 附加属性(在 WPF4 中也称为行为)

您可以创建一个具有附加属性的类,如下所示:

public class MarginSetter
{
    public static Thickness GetMargin(DependencyObject obj)
    {
        return (Thickness)obj.GetValue(MarginProperty);
    }

    public static void SetMargin(DependencyObject obj, Thickness value)
    {
        obj.SetValue(MarginProperty, value);
    }

    // Using a DependencyProperty as the backing store for Margin.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MarginProperty =
        DependencyProperty.RegisterAttached("Margin", typeof(Thickness), typeof(MarginSetter), new UIPropertyMetadata(new Thickness(), CreateThicknesForChildren));

    public static void CreateThicknesForChildren(object sender, DependencyPropertyChangedEventArgs e)
    {
        var panel = sender as Panel;

        if (panel == null) return;

        foreach (var child in panel.Children)
        {
            var fe = child as FrameworkElement;

            if (fe == null) continue;

            fe.Margin = MarginSetter.GetMargin(panel);
        }
    }


}

现在,要使用它,您只需将此附加属性附加到您想要的任何面板,如下所示:

<StackPanel local:MarginSetter.Margin="10">
    <Button Content="hello " />
    <Button Content="hello " />
    <Button Content="hello " />
    <Button Content="hello " />
</StackPanel>

当然可以完全重复使用。

【讨论】:

  • 唯一的问题是它是静态工作的:如果您在面板被实例化后添加/删除子项,那将不起作用。
  • 您的附加行为可能会订阅LayoutUpdated,并根据需要为新项目设置正确的边距。
  • 在运行时 CreateThicknesForChildren 事件在添加任何孩子之前被调用。如何修复此代码,使其不仅适用于设计器?
  • 注册到面板的事件之一,该事件将在孩子已经被添加之后发生。我猜 Loaded 可能会成功。
  • 在标记方面,与 HTML 和 CSS(LESS、SASS)相比,WPF 是多么的麻烦。
【解决方案3】:
<Rectangle Width="3"/>

【讨论】:

    【解决方案4】:

    接受的答案不再有效。但我使用该答案和该答案的作者 (Elad Katz) 的博客来制作我在此处复制的工作代码(在 .Net Core 中测试):

        public static class EstablecedorMargen { 
    
    
        public static Thickness GetMargen(DependencyObject objeto) => objeto != null ? (Thickness)objeto.GetValue(PropiedadMargen) : new Thickness();
    
        public static void SetMargen(DependencyObject objeto, Thickness value) => objeto?.SetValue(PropiedadMargen, value);
    
        public static readonly DependencyProperty PropiedadMargen 
            = DependencyProperty.RegisterAttached("Margen", typeof(Thickness), typeof(EstablecedorMargen), new UIPropertyMetadata(new Thickness(), Cambió));
    
    
        public static void Cambió(object sender, DependencyPropertyChangedEventArgs e) {
            if (!(sender is Panel panel)) return;
            panel.Loaded += new RoutedEventHandler(EstablecerMargenControlesHijos);
        } 
    
    
        public static void EstablecerMargenControlesHijos(object sender, RoutedEventArgs e) {
    
            if (!(sender is Panel panel)) return;
            foreach (var hijo in panel.Children) {
                if (!(hijo is FrameworkElement feHijo)) continue;
                feHijo.Margin = GetMargen(panel);
            }
    
        } 
    
    
    } 
    

    然后你使用:

       <StackPanel local:EstablecedorMargen.Margen="10" >          
                <Button Content="1" />
                <Button Content="2" />
                <Button Content="3" />
        </StackPanel>
    

    【讨论】:

      【解决方案5】:

      我发现在堆栈面板内创建一个网格,然后添加所需的列数(或行数)如下:

          <StackPanel Grid.Row="1" Grid.Column="0" Height="34" Width="698" Margin="10,5,10,10" Orientation="Horizontal"  HorizontalAlignment="Center" VerticalAlignment="Center" >
              <Grid Width="698" Margin="0,0,0,0">
                  <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="*"/>
                      <ColumnDefinition Width="*"/>
                      <ColumnDefinition Width="*"/>
                  </Grid.ColumnDefinitions>
                  <Button x:Name="StartButton" Content="Start" Grid.Row="0" Grid.Column="0" Style="{StaticResource 3DButton}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="70" Click="StartButton_Click" />
                  <Button x:Name="HelpButton"  Content="Help"  Grid.Row="0" Grid.Column="1" Style="{StaticResource 3DButton}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="70" Click="HelpButton_Click"  />
                  <Button x:Name="ExitButton"  Content="Exit"  Grid.Row="0" Grid.Column="2" Style="{StaticResource 3DButton}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="70" Click="ExitButton_Click" Foreground="Red" />
              </Grid>
          </StackPanel>
      

      【讨论】:

      • 您可以省略堆栈面板并获得相同的效果。顺便说一句,默认情况下,Grid 将拉伸到其父级。给它一个固定的宽度是不必要的,所以这是一个坏主意,因为父级可能会在以后调整大小。 WPF 布局使用大量的自动调整大小和拉伸到父级。
      猜你喜欢
      • 2013-12-30
      • 1970-01-01
      • 2010-12-01
      • 2011-05-25
      • 2011-09-13
      • 1970-01-01
      • 1970-01-01
      • 2017-08-23
      • 2019-03-28
      相关资源
      最近更新 更多