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.