如何在StackPanel中设置控件间距?

21

有没有一种简单的方法来设置 StackPanel 内部项之间的默认间距,以便我不必在每个项上设置 Margin 属性?


4
我认为Margin是这里最简单的方法...它们通常是相同类型的项目吗?您可以使用隐式样式为每个项目设置Margin... - kiwipom
也许我可以使用样式来为某些基本类型设置边距?例如,“控件”。 - Poma
1
还可以在这里查看被接受的答案:https://dev59.com/uXNA5IYBdhLWcg3wgeKk - Mike
5个回答

52

我使用了一个透明分隔符,效果很好:

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

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

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

附加属性也可以实现此目的,但我认为这有些过度了。


@Microsoft,太遗憾了,这在UWP上不受支持... :'( - visc
我该怎么使用它?我是否需要在每个子元素后手动添加一个“分隔符”元素?我不明白这比直接设置每个子项的“Margin”属性更好在哪里。我有什么遗漏吗? - Dan Stevens

14

如果所有的控件都相同,那么按照IanR的建议实现一个能够捕捉到该控件的样式。否则,你不能为基类创建一个默认样式,因为这样是行不通的。

在这种情况下最好的方法是使用一个非常巧妙的技巧-附加属性(也称为WPF4中的Behaviors)。

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

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>

当然完全可重复使用。


2
唯一的问题是它是静态的:如果在面板实例化后添加/删除子元素,那就行不通了。 - Mario Vernari
2
你附加的行为可能可以订阅 LayoutUpdated,并根据需要为新项设置正确的边距。 - Jens
1
在运行时,在添加任何子元素之前,将调用CreateThicknesForChildren事件。如何修复此代码,使其不仅在设计器上工作? - Poma
1
在孩子们已经添加后,注册参加面板中的一个活动。我猜Loaded可能会有用。 - Elad Katz
1
当涉及到标记时,WPF相对于HTML和CSS(LESS,SASS)有多么方便而繁琐。 - Mike de Klerk
显示剩余3条评论

-1
<Rectangle Width="3"/>

-2
我发现在堆栈面板内创建网格,然后按如下添加所需数量的列(或行):
    <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>

你可以直接省略StackPanel并获得相同的效果。顺便说一下,Grid默认会拉伸到其父级。给它一个固定的宽度是不必要的,也是一个坏主意,因为父级可能会在以后被调整大小。WPF布局使用了很多自动调整大小和拉伸到父级的功能。 - 15ee8f99-57ff-4f92-890c-b56153

-2

已经接受的答案不再适用。但是我使用了那个答案和那个答案的作者(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>

留下一些英文代码会更好,这样人们可以更容易地跟踪代码。这是一个国际社区,而不是西班牙语社区。 - Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接