0

The behavior I am aiming for is: I have a data grid with a single column. It is bound to a list of items which contain various information about a person. When not selected, the row simply displays the person's name. When the row is selected (i.e. clicked on), I was to show more information about the person.

My first attempt was to use a DataGridTemplateColumn where the CellTemplate is a ContentControl. The style of the ContentControl is determined by the status of the selected row.

My style:

<DataTemplate x:Key="NotSelectedTemplate">
    <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentControl}, Path=DataContext.PatientName.FormattedName, Mode=OneWay, BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>

<DataTemplate x:Key="SelectedTemplate">
    <TextBlock Height="60" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentControl}, Path=DataContext.PatientName.FormattedName, Mode=OneWay, BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged}" />
   </DataTemplate>

<Style x:Key="SelectableContentStyle" TargetType="{x:Type ContentControl}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=IsSelected}" Value="False">
            <Setter Property="ContentTemplate" Value="{StaticResource NotSelectedTemplate}" />
        </DataTrigger>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=IsSelected}" Value="True">
            <Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

My datagrid columns:

<DataGrid.Columns>
    <DataGridTemplateColumn Width="*">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <ContentControl Style="{StaticResource SelectableContentStyle}" />
             </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid.Columns>

This approach works, however the binding in each DataTemplate is pretty ugly. I am relatively inexperienced at WPF, so I'm sure there must be a much better way to implement this.

Basically, 1) Is there a better way to acheive this behavior? 2) Is there a better way to bind to the DataTemplate so I am not chasing RelativeSources any time I want to access a property?

H.B.
  • 166,899
  • 29
  • 327
  • 400
krames
  • 569
  • 1
  • 6
  • 12
  • That is pretty much how i would do it. – H.B. Oct 27 '16 at 19:17
  • I see. The bindings in the DateTemplates are very ugly though. Considering I will have 5+ textblock/properies bindings, I was hoping there was a cleaner way do the binding within each DataTemplate. – krames Oct 27 '16 at 19:20

1 Answers1

0

You could implement a template selector for the ContentTemplateProperty which takes two templates as properties and has one boolean property to switch between them.

The bad news is that the base class (DataTemplateSelector) is not a dependency object and as such does not support a binding for your flag property. In those cases i work around that by adding a Config property that holds an instance of a custom class which you then can make a sub-class of DependencyObject and define dependency properties there. This of course will bloat your code again, and bindings will have limitations because, informally speaking, the binding scopes break.


Another option might be to reference the two templates in the SelectableContentStyle via DynamicResource, that way you just need to write that DataTrigger switch once and merely define the two templates in the resources within the individual DataTemplates.

See this answer for an example.

Community
  • 1
  • 1
H.B.
  • 166,899
  • 29
  • 327
  • 400