What is the easy way to set spacing between items in StackPanel? What is the easy way to set spacing between items in StackPanel? wpf wpf

What is the easy way to set spacing between items in StackPanel?


I use a transparent separator, which works well:

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

You can of course use margins but then if you want to change the margins you have to update all of the elements.

The separator can even be styled in a static resource.

An attached property could do it too but I think it's overkill.


if all the controls are the same then do as IanR suggested and implement a Style that catches that control. if it's not then you can't create a default style to a base class because it just won't work.

the best way for situations like these is to use a very neat trick - attached properties (aka Behaviors in WPF4)

you can create a class that has an attached property, like so:

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

now, to use it, all you need to do is to attach this attached property to any panel you want, like so:

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

Completely reusable of course.


The accepted answer doesn't work anymore. But I used that answer and the blog the author of that answer (Elad Katz) to make a working code (tested in .Net Core) that I reproduce here:

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

Then you use:

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