WPF Grid’s Row/Column Count Properties

One of my pet peeves with using WPF is that a Grid needs to have it’s Rows and Columns defined. One day I decided I was tired of messing with Row/Column definitions for simple Grids, so sat down to write some AttachedProperties.

Now, instead of writing something like this:


<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
</Grid>

I can write this:


<Grid local:GridHelpers.RowCount="6"
      local:GridHelpers.StarRows="5"
      local:GridHelpers.ColumnCount="4"
      local:GridHelpers.StarColumns="1,3">

</Grid>

I can also use this to draw a Grid with a dynamic number of rows or columns, or where I don’t know the number of rows/columns beforehand such as an ItemsPanelTemplate for an ItemsControl.


<Grid local:GridHelpers.RowCount="{Binding RowCount}"
      local:GridHelpers.ColumnCount="{Binding ColumnCount}" />

GridHelpers Code

Here is the AttachedProperty code:

public class GridHelpers
{
    #region RowCount Property
    
    /// <summary>
    /// Adds the specified number of Rows to RowDefinitions. 
    /// Default Height is Auto
    /// </summary>
    public static readonly DependencyProperty RowCountProperty =
        DependencyProperty.RegisterAttached(
            "RowCount", typeof(int), typeof(GridHelpers),
            new PropertyMetadata(-1, RowCountChanged));
    
    // Get
    public static int GetRowCount(DependencyObject obj)
    {
        return (int)obj.GetValue(RowCountProperty);
    }
    
    // Set
    public static void SetRowCount(DependencyObject obj, int value)
    {
        obj.SetValue(RowCountProperty, value);
    }
    
    // Change Event - Adds the Rows
    public static void RowCountChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || (int)e.NewValue < 0)
            return;
    
        Grid grid = (Grid)obj;
        grid.RowDefinitions.Clear();
    
        for (int i = 0; i < (int)e.NewValue; i++)
            grid.RowDefinitions.Add(
                new RowDefinition() { Height = GridLength.Auto });
    
        SetStarRows(grid);
    }
    
    #endregion
    
    #region ColumnCount Property
    
    /// <summary>
    /// Adds the specified number of Columns to ColumnDefinitions. 
    /// Default Width is Auto
    /// </summary>
    public static readonly DependencyProperty ColumnCountProperty =
        DependencyProperty.RegisterAttached(
            "ColumnCount", typeof(int), typeof(GridHelpers),
            new PropertyMetadata(-1, ColumnCountChanged));
    
    // Get
    public static int GetColumnCount(DependencyObject obj)
    {
        return (int)obj.GetValue(ColumnCountProperty);
    }
    
    // Set
    public static void SetColumnCount(DependencyObject obj, int value)
    {
        obj.SetValue(ColumnCountProperty, value);
    }
    
    // Change Event - Add the Columns
    public static void ColumnCountChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || (int)e.NewValue < 0)
            return;
    
        Grid grid = (Grid)obj;
        grid.ColumnDefinitions.Clear();
    
        for (int i = 0; i < (int)e.NewValue; i++)
            grid.ColumnDefinitions.Add(
                new ColumnDefinition() { Width = GridLength.Auto });
    
        SetStarColumns(grid);
    }
    
    #endregion
    
    #region StarRows Property
    
    /// <summary>
    /// Makes the specified Row's Height equal to Star. 
    /// Can set on multiple Rows
    /// </summary>
    public static readonly DependencyProperty StarRowsProperty =
        DependencyProperty.RegisterAttached(
            "StarRows", typeof(string), typeof(GridHelpers),
            new PropertyMetadata(string.Empty, StarRowsChanged));
    
    // Get
    public static string GetStarRows(DependencyObject obj)
    {
        return (string)obj.GetValue(StarRowsProperty);
    }
    
    // Set
    public static void SetStarRows(DependencyObject obj, string value)
    {
        obj.SetValue(StarRowsProperty, value);
    }
    
    // Change Event - Makes specified Row's Height equal to Star
    public static void StarRowsChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || string.IsNullOrEmpty(e.NewValue.ToString()))
            return;
    
        SetStarRows((Grid)obj);
    }
    
    #endregion
    
    #region StarColumns Property
    
    /// <summary>
    /// Makes the specified Column's Width equal to Star. 
    /// Can set on multiple Columns
    /// </summary>
    public static readonly DependencyProperty StarColumnsProperty =
        DependencyProperty.RegisterAttached(
            "StarColumns", typeof(string), typeof(GridHelpers),
            new PropertyMetadata(string.Empty, StarColumnsChanged));
    
    // Get
    public static string GetStarColumns(DependencyObject obj)
    {
        return (string)obj.GetValue(StarColumnsProperty);
    }
    
    // Set
    public static void SetStarColumns(DependencyObject obj, string value)
    {
        obj.SetValue(StarColumnsProperty, value);
    }
    
    // Change Event - Makes specified Column's Width equal to Star
    public static void StarColumnsChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || string.IsNullOrEmpty(e.NewValue.ToString()))
            return;
    
        SetStarColumns((Grid)obj);
    }
    
    #endregion
    
    private static void SetStarColumns(Grid grid)
    {
        string[] starColumns = 
            GetStarColumns(grid).Split(',');
    
        for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
        {
            if (starColumns.Contains(i.ToString()))
                grid.ColumnDefinitions[i].Width = 
                    new GridLength(1, GridUnitType.Star);
        }
    }
    
    private static void SetStarRows(Grid grid)
    {
        string[] starRows = 
            GetStarRows(grid).Split(',');
    
        for (int i = 0; i < grid.RowDefinitions.Count; i++)
        {
            if (starRows.Contains(i.ToString()))
                grid.RowDefinitions[i].Height = 
                    new GridLength(1, GridUnitType.Star);
        }
    }
}
    

43 Responses to WPF Grid’s Row/Column Count Properties

  1. Dominic says:

    You’re awesome !
    That is exactly what I was looking for

  2. T.Koller says:

    Very nice helper-functions!
    I would suggest the following improvements:

    Setting StarColumns and StarRows if they are not set explicitly:

    private static void SetStarRows(Grid grid)
    {
    string[] starRows;

    if (string.IsNullOrWhiteSpace(GetStarRows(grid)))
    {
    starRows = new string[grid.RowDefinitions.Count];
    for (var i = 0; i < grid.RowDefinitions.Count; i++)
    starRows[i] = i.ToString();
    }
    else
    {
    starRows = GetStarRows(grid).Split(',');
    }
    ….
    private static void SetStarColumns(Grid grid)
    {
    string[] starColumns;

    if (string.IsNullOrWhiteSpace(GetStarColumns(grid)))
    {
    starColumns = new string[grid.ColumnDefinitions.Count];
    for (var i = 0; i < grid.ColumnDefinitions.Count; i++)
    starColumns[i] = i.ToString();
    }
    else
    {
    starColumns = GetStarColumns(grid).Split(',');
    }

  3. John says:

    This is what I was looking for but when I put a textblock inside of the grid in one of the columns it tells me that my column range is only (0-0). How do I select which column I want to put the textblock in?

  4. Ankita says:

    This is exactly what i am looking right now, Thanks for the help

    However, i am not able to set the RowCount and Column Count. I have added teh GridHelper.cs and added the xmlns: local at top of my XAML page.

    Where to set the RowCount ?

  5. Swami says:

    Thank you for this. I have used the same Grid Row Definition set up in my application. While displaying the data grid, it just hangs. (about 100+ rows) Is there any limit for the data grids to display the number of rows even though we set up “Auto” or “*” ? I am rendering the data grid with Silverlight.

  6. Jack Frost says:

    Ok, I’m gonna steal this class and keep it in my vault! FOREVER!! Joke 😛 Thanks so much for this Rachel! 🙂

  7. Wei says:

    Hi Rachel,

    I tried your GridHelpers and it’s very handy and useful.

    However, I have encountered an very small issue, which is that NullReferenceException occurred in the code e.NewValue.ToString() in void StarRowsChanged, when I bind GridHelpers.StarRows to a null string. To resolve this issue, simply change e.NewValue.ToString() to e.NewValue?.ToString().

    I understand that binding this attached property to a null string is meaningless, but just in case that someone unpurposely set the property to null.

    PS: similar issue will occur when binding GridHelpers.StarColumns to null.

    Environment: .NET 4.5.2/WIn7 x64/Visual Studio Community 2015 with Update 1

    • Rachel says:

      Thanks Wei, that is useful to know! In most cases, I don’t mind throwing exceptions in my converters so it tells me there is a problem I need to address, however in cases where null is an acceptable value, this is a good change to make.

  8. David Niesel says:

    Hello Rachel,

    an identical class / source code can be found here:
    http://modernuicharts.codeplex.com/SourceControl/latest#ModernUIChart/De.TorstenMandelkow.MetroChart/Controls/GridHelpers.cs

    As your post is from 2011 and the first upload on CodePlex is from 2012, I guess you are the original author of that code. Is that correct?

    If yes, can you grant me following rights without any obligations:
    – Use the code in a proprietary software
    – Modify the code as part of a properietary software
    – Re-distribute the code as part of a proprietary software

    Hope to hear from you (either as private email or as comment on this site).

    • Rachel says:

      Hi David, yes you are welcome to use the code for any project you have. It is pretty basic, and would be easy to replicate by anyone who wanted the same functionality. Thank you for checking with me!

  9. kiran says:

    Hi Rachel, Thank you for the nice post. Is this code has any licensing or can we use this in our program ? Comes under Open Source license or any other. Please let us know. Thank you.

  10. janstrings says:

    Excellent! I needed this so thank you. I don’t know why Microsoft didn’t think of this :p

  11. skippyvondrake says:

    Thanks for your GridHelper. Very Handy! I use it all the time.

  12. Marcin says:

    Hi!
    Is there a possibility to add ItemSource propertz to grid control and fill cells by binding?

    • Rachel says:

      Hi Marcin,

      If that is your requirement, I’d recommend looking into an ItemsControl with an ItemsTemplate overridden to use a Grid or UniformGrid. Make sure you also set the ItemContainerStyle so it binds Grid.Row and Grid.Column properties too!

      Thanks,
      Rachel

  13. skippyv says:

    Very convenient. I use it all the time now! Thanks!!

  14. Matthew Cuba says:

    Nice solution Rachel. Thanks for sharing!

  15. Rakesh says:

    Rachel, How to define rowcount and column count? I am not getting how to set rowcount and columncount in the above code

    • Rachel says:

      Hi Rakesh, you’ll need to make sure you have an xmlns setup at the top of your Window or UserControl that points to the namespace of your class containing the Grid’s attached properties. If you’re having problems with it, I’d suggest asking a question on StackOverflow with your code and a description of your problem, and I’m sure someone could help you out. If you wanted you could even leave the link to your question here and I could take a look if nobody else helps you out first =)

  16. DB says:

    Hi Rachel,
    Is there any source code for this? I have a quick question, are you create a class and inherits the control as your base? Else, how are you able to create dependency properties for that. Please advise.

    Thank you.

    • Rachel says:

      Hi DB,

      No, we do not have to inherit the Grid for this. That’s the beauty of Dependency Properties – they can be used to define a property that can be attached to any class, and do not have to exist on that class itself. The only code used is included in the post.

      Thanks,
      Rachel

  17. jeffman19 says:

    Can you please elaborate on where RowCount and ColumnCount would be defined? I tried defining them as properties in my MainWindow but they’re not binding. Are these properties supposed to be defined somewhere in particular?

    • Rachel says:

      In my case, I put them in their own class called GridHelpers and make sure that class is in a namespace that is defined in my XAML using an xmlns alias. In the example, I used the alias “local”, so can refer to the properties using “local:GridHelpers.RowCount”.

  18. Richard says:

    Hi Rachel,it is an excellent post. I am new on WPF and I would like to know if it is possible to add a GridSplitter between each column for example:
    column | gridsplitter | columns
    column | gridsplitter | column | gridsplitter | column

    If you can help me 🙂

    Thanks,
    Richard

    • Rachel says:

      Hi Richard, I don’t think that can be easily done with a simple Attached Property.

      The problem is you’d need to insert the GridSplitter between the ContentPresenter objects, which means you’d really need (ColumnCount * 2) – 1 Columns to account for the GridSplitters, and you’ll have to adjust the Grid.Column property of all child objects except the first one to place them at Grid.Column * 2, or they’ll overlap the GridSplitter columns.

      Such complexity is probably better suited for a new custom panel instead of an Attached Property.

  19. Stefan says:

    Hi,

    first of all, thanks for the great code! I wanted to use it on my Windows Phone 8 project, but got a strange “Ambiguous match found” error message from the compiler.

    The solution is to rename the *private* methods SetStarRows and SetStarColumns to something else, like DoSetStarRows and DoSetStarColumns. For some reason, the compiler does not like having private methods named exactly like the public methods…

    Hope that helps,
    Stefan

    • Vadim says:

      Rachel, thanks for your blog!
      Stefan, thanks for your solution!
      I’ve got “Ambiguous match found” error message too. It happened when I tried to bind all four properties.

  20. I wish I had run across this sooner, I’ve been trying to figure out how to do this for a while. I figured it would be easy to do, I just had no clue where to start. Thanks for posting this.

  21. Angavar says:

    Hi Rachel, I really admire your work here and on StackOverflow! Keep it up!

  22. Julien says:

    Hi,

    I’m using it in order to add ItemsControl items in the ItemsPanelTemplate as a Grid but the items always appear in the column 0 of my grid even if I bind the Grid.Column property in the ItemContainerStyle to a ColumnCount dp in my VM…

    Any guess why?

    • Julien says:

      i just found a way to do it, i just had to add this part at the end of the ColumnCountChanged event:

      for (int i = 0; i < childCount; i++)
      {
      var child = grid.Children[i] as FrameworkElement;
      Grid.SetColumn(child, i);
      }

      and i used a converter for a binding on a ColumnCount Property in my ViewModel to make all the column equally sized andd tadaa!!! it worked!!!

      thx anyway for all your amazing pieces of code!

  23. Sam Naseri says:

    Hi,

    Thanks for your great post. I have done the same thing but slightly different. The advantage of your approach is that it suitable for binding.
    I have posted my approach here:
    http://samondotnet.blogspot.com.au/2012/03/wpf-grid-layout-simplified-using-rows.html

  24. x says:

    Wow! Works in design time too! Thanks a lot!

  25. Frank Wu says:

    Cool! I can see part of the code on iPad There is no scroll bar somehow.

    • Rachel says:

      Hi Frank,

      I’ll have to report that bug to WordPress. You should be able to highlight the code and drag your mouse to scroll/copy it since it’s all there. It’s just not showing the scrollbars. You can also use View Source to see it. Thanks for letting me know of that!

  26. Very neat! I’ll definitely find this handy, thanks 🙂

Leave a reply to Vadim Cancel reply