Pixelbrei in High Definition Das Ende der Welt

A Simplified Grid Markup Reloaded

Published on Sunday, January 2, 2011 8:35:00 AM UTC in Programming

This morning I had to type a lot of grid definitions manually (would've been so much easier with Blend...), and I remembered a post by Colin Eberhardt I had read some time ago, about a simplified grid markup for Silverlight (and WPF). The idea behind it is nice, and when I had to type something like this:

<StackPanel Grid.Row="2"
            Grid.Column="1"
            Grid.ColumnSpan="2">

... for the fifth time, I took a little break and extended Colin's approach to include the above declarations.

A word of caution

Neither Colin's approach nor what I describe in the following fully works with Blend. The designer shows the result correctly, but you're not able to edit these grids other than directly in XAML. So I see this more like a fun snippet, as it probably is only useful for you if you don't plan on using Blend.

A Grid Cell attached property

As extension to Colin's approach, I've added an attached property named "Cell":

/// <summary>
/// Identifies the Cell attached property
/// </summary>
public static readonly DependencyProperty CellProperty =
    DependencyProperty.RegisterAttached("Cell", typeof(string), typeof(GridUtils),
        new PropertyMetadata("", new PropertyChangedCallback(OnCellPropertyChanged)));

/// <summary>
/// Gets the value of the Cell property
/// </summary>
public static string GetCell(DependencyObject d)
{
    return (string)d.GetValue(CellProperty);
}

/// <summary>
/// Sets the value of the GridLocation property
/// </summary>
public static void SetCell(DependencyObject d, string value)
{
    d.SetValue(CellProperty, value);
}

The interesting part is the "OnCellPropertyChanged" method, where all the magic happens. The value of the attached property is split, and each of the single values is used to set the respective "Grid" property for the associated object:

/// <summary>
/// Handles the property changed event for the Cell property, setting the
/// Row, Column, RowSpan and ColumnSpan values on the element which this property is attached to.
/// </summary>
private static void OnCellPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    // parse the location
    string locationDefs = e.NewValue as string;
    var locationDefArray = locationDefs.Split(',');

    for (int i = 0; i < locationDefArray.Length; i++)
    {
        string locationDef = locationDefArray[i].Trim();

        // if a value is missing, use zero
        if (string.IsNullOrEmpty(locationDef))
        {
            locationDef = "0";
        }

        int locationValue;
        if (int.TryParse(locationDef, out locationValue))
        {
            // the order is: row, column, rowspan, columnspan
            switch (i)
            {
                case 0:
                    d.SetValue(Grid.RowProperty, locationValue);
                    break;
                case 1:
                    d.SetValue(Grid.ColumnProperty, locationValue);
                    break;
                case 2:
                    d.SetValue(Grid.RowSpanProperty, locationValue > 0 ? locationValue : 1);
                    break;
                case 3:
                    d.SetValue(Grid.ColumnSpanProperty, locationValue > 0 ? locationValue : 1);
                    break;
            }
        }
    }
}

How to use it

With that, my initial sample of this post becomes something like:

<StackPanel local:GridUtils.Cell="2,1,2">

One can argue if this is simpler than the original notation, as you have to remember the order of values (row, column, row span, column span), but if you type a lot of grid definitions manually, it might save you quite some time eventually.

Here you can download the complete source code; it also includes Colin's original sample which I've reworked to use the above syntax. Note that the source code also includes the proposed fix for a problem with the original code someone pointed out in the comments of Colin's post. Have fun ;).

SimplifiedGridSilverlight.zip (7.84 kb)

Tags: Fun With Code · Silverlight