Wouldn't it be nice if the WPF
Grid control had a '
Padding' property? In this article, I will show you how to create the
PaddedGrid control, a custom control that derives from
Grid and provides this much needed property.
Here's a picture of the
PaddedGrid being used in the Visual Studio XAML designer window. As you can see, the labels and text boxes are spaced apart from each other by the amount specified in the
I often use
Grids for laying out data entry sections of forms. Typically, there will be a column of
Labels on the left and a column of fields on the right. As the
Grid control doesn't have a
Padding property, the
Margin of the controls in the
Grid has to be set to an appropriate value to space things out properly. This can clutter up the XAML, and is a bit time consuming. Having a
Padding property on the parent
Grid makes things much cleaner.
Planning the Control
Before I go through the control code step-by-step, I'll explain how the padding will work.
With WPF, there are generally many ways to achieve things like this; each technique will have its own benefits and drawbacks. Ideally, we would wrap each grid cell in a container of some kind, and set the margin on that. This would give the correct layout in all cases, but is needlessly complex. A more simple solution is to have the control do what I have been doing manually - set the margin property of the child controls. In fact, if we can bind the
Margin property of the grid's immediate children to the
Padding property of the parent
PaddedGrid, then we will have what we need.
By binding the children's
Margin to the parent's
Padding (a technique that is commonly used in DataTemplates, ItemTemplates, and so on), we avoid the need to do any complicated custom layout in procedural code. By making
Padding a Dependency Property, we keep the
PaddedGrid consistent with the standard WPF controls.
The PaddedGrid Control
I'll take you through the
PaddedGrid control step-by-step. I've tried to do this in the most logical order for the article; the code file itself is in a slightly different order. Here we go:
public class PaddedGrid : Grid
private static readonly DependencyProperty PaddingProperty =
new UIPropertyMetadata(new Thickness(0.0),
First, we create the class and derive it from
Grid. Then we create the static Dependency Property for
Padding. Dependency Properties are absolutely critical to WPF; if you are unfamiliar with them, start with the MSDN article: 'Dependency Properties Overview'.
We register the Dependency Property as a
Thickness type. This is the same data type as the
Margin property that most controls have. It allows a padding on the left, right, top, and bottom to be specified (or a single padding for each side). The default value is set to zero, which means that, by default, the
PaddedGrid will look just like a standard grid. One thing to note is that we also specify a
PropertyChangedCallback - this will be called every time
Padding is changed. More on this later.
Loaded += new RoutedEventHandler(PaddedGrid_Loaded);
The constructor is very straightforward - it simply adds an event handler for the
Loaded event. It is in the
Loaded event handler that we will bind the
Margin properties of the child controls to the
Padding property of the
void PaddedGrid_Loaded(object sender, RoutedEventArgs e)
int childCount = VisualTreeHelper.GetChildrenCount(this);
for (int i = 0; i < childCount; i++)
DependencyObject child = VisualTreeHelper.GetChild(this, i);
DependencyProperty marginProperty = GetMarginProperty(child);
if (marginProperty != null)
Binding binding = new Binding();
binding.Source = this;
binding.Path = new PropertyPath("Padding");
BindingOperations.SetBinding(child, marginProperty, binding);
We use the
VisualTreeHelper to get the number of immediate children in the visual tree. We can then use a loop and the
VisualTreeHelper to get each child as a DependencyObject. By calling the helper function
GetMarginProperty (which is described later), we attempt to get the
Margin property for the child. If it exists, we create a binding to the
Padding property; then we set it to the
Margin property of the child. This way, each immediate child will have its
Margin property bound to the
Padding of the parent
By using a binding like this, we ensure that changes to the padding at run-time will be correctly reflected in the
Margin of each child control.
protected static DependencyProperty GetMarginProperty(DependencyObject dependencyObject)
foreach (PropertyDescriptor propertyDescriptor in
DependencyPropertyDescriptor dpd =
if (dpd != null && dpd.Name == "Margin")
Margin dependency property for a dependency object is simple enough. We use the
TypeDescriptor object to iterate through each property. The
DependencyPropertyDescriptor.FromProperty function will get a reference to the dependency property - but only if the property is a dependency property (rather than a standard property). If it isn't, it will return
null. This is the quickest way I found to enumerate the dependency properties.
If we have found a dependency property, we check to see if it is the '
Margin' property. If it is, we return it. Easy!
This function could be generalised to find any dependency property by name, but I'm keeping things simple in the article to make sure that the logic is easy to follow.
The last thing to do is implement the
OnPaddingChanged callback we set in the constructor of the
Padding dependency property.
private static void OnPaddingChanged(DependencyObject dependencyObject,
PaddedGrid paddedGrid = dependencyObject as PaddedGrid;
The callback is very simple. We get the
PaddedGrid that has had its padding changed and force it to update its layout.
Using the PaddedGrid
First, add a reference to the PaddedGrid assembly to your project, then add the namespace in the XAML of the
Page) that you will use it in:
Title="MainWindow" Height="350" Width="525">
Once you have the namespace defined, you can use the
PaddedGrid (and its
Padding) like so:
<paddedGrid:PaddedGrid x:Name="paddedGrid" Padding="2,6,3,6" >
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
<RowDefinition Height="Auto" />
<Label Grid.Row="0" Grid.Column="0">Name</Label>
<TextBox Grid.Row="0" Grid.Column="1" Text="Enter Name Here" />
I have only used the
PaddedGrid in fairly simple layouts. The trick of setting the margin of the immediate children may not work in every case. This is a simple control for simple scenarios - however, if you have any problems with it, do let me know and I will endeavour to resolve the issue and post updates.
If you have any suggestions for improvements, then let me know. I'd be happy to extend the control and the article if there is more that could be done!
The PaddedGrid library and a sample project can be downloaded from the link above. Enjoy!