Skip to content

Instantly share code, notes, and snippets.

@angularsen
Created January 17, 2015 12:19
Show Gist options
  • Save angularsen/90040fb174f71c5ab3ad to your computer and use it in GitHub Desktop.
Save angularsen/90040fb174f71c5ab3ad to your computer and use it in GitHub Desktop.
WPF - Automatic horizontal or vertical spacing in StackPanel and other list like panels
<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>
<StackPanel Orientation="Vertical" foo:MarginSetter.Margin="5" foo:MarginSetter.LastItemMargin="5 0">
<Button>Button 1</Button>
<Button>Button 2</Button>
</StackPanel>
using System.Windows;
using System.Windows.Controls;
using JetBrains.Annotations;
namespace Foo
{
public class MarginSetter
{
private static Thickness GetLastItemMargin(Panel obj)
{
return (Thickness) obj.GetValue(LastItemMarginProperty);
}
[UsedImplicitly]
public static Thickness GetMargin(DependencyObject obj)
{
return (Thickness) obj.GetValue(MarginProperty);
}
private static void MarginChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
{
// Make sure this is put on a panel
var panel = sender as Panel;
if (panel == null) return;
// Avoid duplicate registrations
panel.Loaded -= OnPanelLoaded;
panel.Loaded += OnPanelLoaded;
if (panel.IsLoaded)
{
OnPanelLoaded(panel, null);
}
}
private static void OnPanelLoaded(object sender, RoutedEventArgs e)
{
var panel = (Panel) sender;
// Go over the children and set margin for them:
for (var i = 0; i < panel.Children.Count; i++)
{
UIElement child = panel.Children[i];
var fe = child as FrameworkElement;
if (fe == null) continue;
bool isLastItem = i == panel.Children.Count - 1;
fe.Margin = isLastItem ? GetLastItemMargin(panel) : GetMargin(panel);
}
}
[UsedImplicitly]
public static void SetLastItemMargin(DependencyObject obj, Thickness value)
{
obj.SetValue(LastItemMarginProperty, value);
}
[UsedImplicitly]
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(), MarginChangedCallback));
public static readonly DependencyProperty LastItemMarginProperty =
DependencyProperty.RegisterAttached("LastItemMargin", typeof (Thickness), typeof (MarginSetter),
new UIPropertyMetadata(new Thickness(), MarginChangedCallback));
}
}
using System.Windows;
using JetBrains.Annotations;
namespace Foo
{
public class Spacing
{
public static double GetHorizontal(DependencyObject obj)
{
return (double) obj.GetValue(HorizontalProperty);
}
public static double GetVertical(DependencyObject obj)
{
return (double) obj.GetValue(VerticalProperty);
}
private static void HorizontalChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
{
var space = (double) e.NewValue;
var obj = (DependencyObject) sender;
MarginSetter.SetMargin(obj, new Thickness(0, 0, space, 0));
MarginSetter.SetLastItemMargin(obj, new Thickness(0));
}
[UsedImplicitly]
public static void SetHorizontal(DependencyObject obj, double space)
{
obj.SetValue(HorizontalProperty, space);
}
[UsedImplicitly]
public static void SetVertical(DependencyObject obj, double value)
{
obj.SetValue(VerticalProperty, value);
}
private static void VerticalChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
{
var space = (double) e.NewValue;
var obj = (DependencyObject) sender;
MarginSetter.SetMargin(obj, new Thickness(0, 0, 0, space));
MarginSetter.SetLastItemMargin(obj, new Thickness(0));
}
public static readonly DependencyProperty VerticalProperty =
DependencyProperty.RegisterAttached("Vertical", typeof (double), typeof (Spacing),
new UIPropertyMetadata(0d, VerticalChangedCallback));
public static readonly DependencyProperty HorizontalProperty =
DependencyProperty.RegisterAttached("Horizontal", typeof (double), typeof (Spacing),
new UIPropertyMetadata(0d, HorizontalChangedCallback));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment