Marc
Marc

Reputation: 13184

Sharing column width between grids defined in a template

I am trying to layout a couple of controls:

enter image description here

The light gray vertical lines are grid splitters. Each line in this table is a grid with three columns, the label on the left, the splitter in the middle and the control on the right, including the text boxes and the image.

I want all columns to be aligned. Here is the data template I use for each line:

<DataTemplate x:Key="PropertyLineTemplate">
    <Grid Margin="0,0,0,1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition SharedSizeGroup="Name"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition SharedSizeGroup="Value"/>
        </Grid.ColumnDefinitions>

        <TextBlock 
            Grid.Column="0"            
            VerticalAlignment="Center"
            Text="{Binding Title}" /> 

        <GridSplitter Grid.Column="1" Width="2"/>

        <SomeUserControl
            Grid.Column="2"               
            Content="{Binding}"                
            Margin="4, 0, 0, 0"/>
    </Grid>
</DataTemplate>

and the template for the view itself:

<DataTemplate DataType="{x:Type vm:PropertiesViewModel}">
    <DockPanel>            
        <!-- Properties -->
        <ScrollViewer>
            <StackPanel Margin="10">
                <ItemsControl ItemsSource="{Binding Properties}"
                        ItemTemplate="{StaticResource PropertyLineTemplate}" />
            </StackPanel>
        </ScrollViewer>
    </DockPanel>
</DataTemplate>

and the usage of both:

<ContentControl Content="{Binding SelectedItem}" Grid.IsSharedSizeScope="True">          
</ContentControl>

where SelectedItem is of type PropertiesViewModel.

I also tried to place Grid.IsSharedSizeScope="True" in each individual grid directly and on the panels containing the control, without effects. How can I achieve that all columns share the width?

Upvotes: 3

Views: 2299

Answers (2)

Anders
Anders

Reputation: 1643

Grid.IsSharedSizeScope should be set on the first parent ItemsControl of a Grid, in your case it would be the ItemsControl in the ViewModel template. Then the columns width will be adjusted.

However, if you move one GridSplitter, then it will only adjust that row, not the others (See WPF SharedSizeGroup GridSplitter Issue for a potential solution, if you need resizing.)

Other stuff: you don't need the Stackpanel wrapper around the ItemsControl, since the ItemsControl is the only child. If you need to adjust the panel the ItemsControl uses, then set it on the Property ItemsPanel, like this:

<ItemsControl ItemsSource="{Binding Properties}"
              Grid.IsSharedSizeScope="True"
              ItemTemplate="{StaticResource PropertyLineTemplate}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/> <!-- Or <WrapPanel/> or <UniformGrid/> etc. -->
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

However, the Stackpanel is the default panel of the ItemsControl.

Upvotes: 7

Marc
Marc

Reputation: 13184

Based on Nautious' answer I've solved the problem by defining two ColumnDefinitions as resources and binding the Width property of all columns in question to the Width property of these 'master column definitions':

<ColumnDefinition x:Key="MasterColumnDefinition" />

<ColumnDefinition x:Key="MasterColumnDefinition2" />

<DataTemplate x:Key="PropertyLineTemplate">
     <Grid Margin="0,0,0,1">
          <Grid.ColumnDefinitions>
              <ColumnDefinition Width="{Binding Source={StaticResource MasterColumnDefinition}, Path=Width, Mode=TwoWay}"/>
              <ColumnDefinition Width="Auto"/>
              <ColumnDefinition Width="{Binding Source={StaticResource MasterColumnDefinition2}, Path=Width, Mode=TwoWay}"/>
          </Grid.ColumnDefinitions>

          ...
    </Grid>
</DataTemplate>

Might be a little hacky, but it's simple and works. Not, however, that the shared size scope of this solution is the scope in which the resources are defined. I.e. placing these template in the app's resources will lead to all columns in the application being resized synchronously.

Upvotes: 1

Related Questions