Using the WPF Grid control is easy when your child elements are always contained within a single grid cell (i.e. there is no column/row spanning). A fixed width column stays the requested fixed width, an auto column will indeed size itself to be as wide as the widest cell in the column. Star columns share any remainder space according to their relative star values. All is simple in the world.
But once you have a cell that spans two or more columns the width of the columns becomes more complicated to calculate and indeed seems counter-intuitive. Here is a trivial example of what I mean. We can define two columns with the first as auto and the second as fixed at 30 pixels.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
Now we define a button that spans both of the columns and happens to measure at 80 pixels wide. (On my machine with my font and theme settings etc…)
<Button Grid.ColumnSpan="2" Content="QWERTYUIOP"/>
We need to allocate the 80 pixels width of the button across the two spanning columns. Given the second column is fixed at 30 I would expect 30 to be allocated against that column and the remaining 50 go to the first column. Because the first column is auto it seems the obvious thing to do.
But no. If you try this in practice you will find that the first column is 0 pixels and the second column has become the full 80. Even though that second column is defined as fixed and so should not be growing bigger, it as stretched to the full width of the button. Maybe I am missing something here but that does not seem very logical to me.
So to my actual question. Is there a full description of the logic used by the Grid control for doing this calculations so that I can fully understand how it works? I have searched MSDN and Google and find nothing that describes how spanning elements affect the column widths.
Honestly I didn’t believe you when I read this, so I had to go off and test it myself, and indeed you are correct. I don’t think that you’ll have any luck finding rules though because further investigation led me to believe it is a bug in the WPF grid. I performed a number of tests to see if I could figue out the behaviour, but if you just want to know the final conclusions feel free to scroll past the following diatribe.
Sorry if the results aren’t clear, they are how I wrote them as a worked. The first three numbers are the sizing values I put in for each column and rest is the resultant sizes.
Test 1:
Grid 300 X 300 hosting a contol 80 pixels wide. The grid has three columns and the control spans columns 0 and 1:
So from this I can come up with a number of rules:
Test 2:
Grid 300 X 300 with 3 columns hosting one control 80 pixels wide spaning columns 0 and 2 on row 0 and a second control 80 pixels wide only in column 1 of row 1
(*) This isn’t exactly what happens. Column 1 is set to size 80 but only draws part of the non-spanning element. I was using buttons as my elements and the non-spanned button’s chrome filled up the 80 pixel wide first column, but the text was trimmed to a size of 30 pixels. Basically it was completely screwed.
From this test I can add two more rules:
So, I guess we can combine these rules into one overarcing philosophy:
If an elements spans multiple columns and at least one, but not all, of those columns are auto sizing there must be another that doesn’t span to provide a size for the auto sized columns. Otherwise the behaviour is at best unexpected, and at worst corrupting.
Feel free to raise a bug with Microsoft, but since this is now the defined behaviour of the grid control I imagine we’re stuck with it for the lifetime of WPF.