Synchronizing the width of elements in an ItemsControl

When I use an ItemsControl (or subclass of ItemsControl, such as ListBox) to display a list of items, I often want the width of an element in each item to match the width of the equivalent elements displayed for all other items.  That is easy to achieve by setting the Width property of an element in the DataTemplate used by the ItemTemplate property, but using hard-coded width and height values is generally considered to be a bad practice.  It’s better to not specify a width, and let the element figure out how big it should be based on its content.  But, if the element created for each item in the ItemsControl is sizing to its own content, that means that the sizes of all elements created for items will usually not be equal to each other.

For example, the screenshot below displays an ItemsControl populated with some strings.  The ItemsControl has an ItemTemplate that contains a TextBlock with a light blue background color.  Notice how each item is just wide enough to display its content:

What I would like, however, is to have each item be equally wide, and that the width of all items is the width required by the widest item.   In other words, all of the TextBlocks should be as wide as the TextBlock that contains the word ‘Whatever’.  As I mentioned before, I could solve this problem by hard-coding a Width for the TextBlocks, but that is a very fragile solution.

It turns out that there is a very clean and simple solution to this problem.  The trick is to rely on a not-so-often used feature of the Grid panel.  Grid has an attached property called IsSharedSizeScope, which I will set to true on the ItemsControl.  I then wrap the TextBlock in the ItemControl’s ItemTemplate inside a Grid, and give that Grid a single ColumnDefinition whose SharedSizeGroup property is set to some arbitrary identifier.  Here is that XAML:

When I run the application now, the UI looks like this:

You can download the demo project here.  Be sure to change the file extension from .DOC to .ZIP and then decompress the file.

15 Responses to Synchronizing the width of elements in an ItemsControl

  1. Wow – this is crazy great timing! Thanks.

  2. Josh Smith says:

    I’m glad this post helped you out, Ryan. 🙂

    Josh

  3. Nick Ridley says:

    Cheers Josh that is great!

  4. Josh Smith says:

    I agree, Nick. This is one of those tricks that I frequently find useful.

  5. Corrado Cavalli says:

    It’s simple and i works! that’s the kind of solution i like
    Thanks Josh!

  6. Josh Smith says:

    Thanks guys. I like that this simple, handy trick has evoked so many positive responses.

    Josh

  7. peteohanlon says:

    Interesting Josh, but I prefer to stretch the elements to the full size of the list, so I normally go with an autosizing TextBlock. Still, if I want to constrain the sizing, I’ll have bookmarked this one.

  8. […] Smith again with Synchronizing the width of elements in an ItemsControl Corey Shumann shows how to Make a Play / Pause button in Silverlight The guys over at First Floor […]

  9. Tim Hibbard says:

    Hey Josh. Great article as always. I can see the visual difference between your code and using HorizontalContentAlignment=”Stretch”, where obviously, the latter will try to fill as much space as the listbox will allow it. But I was wondering if there would be any performance differences?

  10. Josh Smith says:

    Tim,

    Probably, but I don’t know. If there is a difference, I think it would be so small and inconsequential that it wouldn’t matter.

    Josh

  11. […] Getting all your controls to have the same width in an Items Control – there really is no good way of summarizing what Josh Smith is doing here, but he’s using the fabulous Grid.IsSharedSizeScope property, which is not well known but is fantastically useful for aligning items (especially in WPF forms). […]

  12. Toreador says:

    Hi Josh Smith,

    Using Grid.IsSharedSizeCope property and grid dependency property SharedSizeGroup can we obtain stretch effect on the layout. Say when i stretch the screen do my all columns consistently expand. Please suggest me a way how i can do the same.

    Thanks,

  13. Luay says:

    I am trying to use Grid.IsSharedSizeScope attached property in Silverlight but it seems that MS didn’t include it in Silverlight. I get this error:

    The attachable property ‘IsSharedSizeScope’ was not found in type ‘Grid’.

    Any hints?

  14. Jon says:

    Luay: Another way to get the similar results in Silverlight can be found here: http://silverlight.net/forums/t/16044.aspx
    Basically, you bind the width of each item to the ActualWidth of the ListBox.