I'm always hesitant to call something a bug because often it turns out to be my own misunderstanding. So I won't call this a bug yet, but I'm close…

I sometimes use Grids inside of DataTemplate for an ItemsControl or a ListBox as a means to get a "column" effect for the elements. In this case, I set the parent with a Grid.IsSharedSizeScope="True" and then set the SharedSizeGroup on the ColumnDefinitions in the DataTemplate. Maybe there is a better way, but this works well for many cases.

Recently, I ran into a case where I wanted the contents of the ItemsControl to limit themselves to the width of the containing ScrollViewer's ViewportWidth. I didn't want any horizontal scrolling. Rather, I wanted the contained TextBlocks to wrap their text.

Fail

I tried a number of things to get this to work via the Grid's SharedSizeGroup. In the end, I had to use an alternate approach that used used margins on the elements to put them in the right spot. That works too, and might be a better way for simple scenarios, but I really like the SharedSizeGroups for certain cases.

Here's a sample XAML (built with KaXaml) that demonstrates the issue:

<Page
   xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <ScrollViewer MaxWidth="300" HorizontalScrollBarVisibility="Disabled" x:Name="SV">
     <StackPanel Grid.IsSharedSizeScope="True">
       <StackPanel.Resources>
         <DataTemplate x:Key="ItemRow">
           <Grid Background="LightGray"
                  MaxWidth="{Binding ElementName=SV, Path=ViewportWidth}"
                 Margin="2"
           >
             <Grid.ColumnDefinitions>
               <ColumnDefinition SharedSizeGroup="A" Width="Auto" />
               <ColumnDefinition SharedSizeGroup="B" Width="*" MaxWidth="200" />
               <ColumnDefinition SharedSizeGroup="C" Width="Auto" />
             </Grid.ColumnDefinitions>
             <TextBlock Grid.Column="0" TextWrapping="Wrap" Margin="5,2">
               <Hyperlink>
                 <Run Text="Short" />
               </Hyperlink>
             </TextBlock>
             <TextBlock Grid.Column="1" TextWrapping="Wrap" Margin="5,2">
               <Hyperlink>
                 <Run Text="This is a test of a really long text block in a hyperlink that should probably wrap." />
               </Hyperlink>
             </TextBlock>
             <TextBlock Grid.Column="2" TextWrapping="Wrap" Margin="5,2">
               <Hyperlink>
                 <Run Text="Short" />
               </Hyperlink>
             </TextBlock>
           </Grid>
         </DataTemplate>
       </StackPanel.Resources>
       <ContentPresenter ContentTemplate="{StaticResource ItemRow}" />
       <ContentPresenter ContentTemplate="{StaticResource ItemRow}" />
       <ContentPresenter ContentTemplate="{StaticResource ItemRow}" />
     </StackPanel>
   </ScrollViewer>
 </Page>

 

Which looks like this:

image

In the above, I highlighted the key points. Note that there is a max width on both the Grid and on the ColumnDefinition. Neither of these are honored when the Grid.IsSharedSizeScope="True" is set on the ScrollViewer. However, if you set this to "False", then the thing works correctly and wraps the TextBlocks. In this case, the text is all the same length, but if some of the columns had very short text in the middle column, then things would not align. Hence the need for SharedSizeGroups.

I tried a couple variations, including a ColumnDefinition with a width of "Auto" for the 2nd column. No go.

Workaround

Here's what I did to work around it in this case:

<Page
   xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <ScrollViewer MaxWidth="300" HorizontalScrollBarVisibility="Disabled" x:Name="SV">
     <StackPanel>
       <StackPanel.Resources>
         <DataTemplate x:Key="ItemRow">           <Grid Background="#EEE"
                  Margin="2"
           >
             <TextBlock TextWrapping="Wrap" Margin="5,2" Width="35" HorizontalAlignment="Left" Background="#DDD">
               <Hyperlink>
                 <Run Text="Short" />
               </Hyperlink>
             </TextBlock>
             <TextBlock TextWrapping="Wrap" Margin="45,2,45,2" Background="#DDD">
               <Hyperlink>
                 <Run Text="This is a test of a really long text block in a hyperlink that should probably wrap." />
               </Hyperlink>
             </TextBlock>
             <TextBlock TextWrapping="Wrap" Margin="5,2" Width="35" HorizontalAlignment="Right" Background="#DDD">
               <Hyperlink>
                 <Run Text="Short" />
               </Hyperlink>
             </TextBlock>
           </Grid>
         </DataTemplate>
       </StackPanel.Resources>
       <ContentPresenter ContentTemplate="{StaticResource ItemRow}" />
       <ContentPresenter ContentTemplate="{StaticResource ItemRow}" />
       <ContentPresenter ContentTemplate="{StaticResource ItemRow}" />
     </StackPanel>
   </ScrollViewer>
 </Page>

 

Which looks like this:

image

Again, I highlighted the important settings. Basically, I put everything in a single grid. Then I put a fixed width on all but one of the columns and used margins to put things in the right spot. This works, but it only allows for a single item to be of variable width. It also doesn't allow the "row" to "shrink to fit".

Other Reports

I found a couple related posts on StackOverflow, and a couple of items related to SharedSizeGroups on Microsoft's Connect Site:

What's the Deal?

Maybe this behavior is "by design", but if so, I think it's incorrectly designed or at best, not intuitive.

If anyone can explain this, I'd love to hear an explanation, correction, or better work around.

Cheers!