Search code examples
wpfdatatemplatebindingdatatriggercontentcontrol

Unable to set ContentTemplate via DataTrigger


I want the ContentTemplate to vary according to the value in the DataTrigger.
And yes, I considered using a DataTemplateSelector, but now I need a DataTrigger or better said a MultiDataTrigger.

Please take a look at the following sample app, the DataTemplate doesn't change:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:WpfApplication1">
    <StackPanel>
        <CheckBox IsChecked="{Binding BoolProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:Window1}}}" Content="BoolProperty"/>
        <ContentControl Content="{Binding BoolProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:Window1}}}">
            <ContentControl.ContentTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding BoolProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:Window1}}}" Content="Template 1"/>
                </DataTemplate>
            </ContentControl.ContentTemplate>
            <ContentControl.Resources>
                <DataTemplate x:Key="Template2">
                    <CheckBox IsChecked="{Binding BoolProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:Window1}}}" Content="Template 2"/>
                </DataTemplate>
            </ContentControl.Resources>
            <ContentControl.Style>
                <Style TargetType="ContentControl">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding BoolProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:Window1}}}" Value="True">
                            <Setter Property="ContentTemplate" Value="{StaticResource Template2}"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
        <Button Name="btnSwitch" Content="Switch"/>
    </StackPanel>
</Window>

Partial Class Window1
    Public Property BoolProperty() As Boolean
        Get
            Return GetValue(BoolPropertyProperty)
        End Get
        Set(ByVal value As Boolean)
            SetValue(BoolPropertyProperty, value)
        End Set
    End Property
    Public Shared ReadOnly BoolPropertyProperty As DependencyProperty = DependencyProperty.Register("BoolProperty", GetType(Boolean), GetType(Window1), New FrameworkPropertyMetadata(False))

    Private Sub btnSwitch_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSwitch.Click
        BoolProperty = Not BoolProperty
    End Sub
End Class

Solution

  • Here's something that works for me:

    <ContentControl Content="{Binding SomeBool}">
      <ContentControl.Resources>
        <DataTemplate x:Key="PinkTemplate">
          <TextBlock Text="{Binding}" Background="Pink" />
        </DataTemplate>
        <DataTemplate x:Key="LimeTemplate">
          <TextBlock Text="{Binding}" Background="Lime" />
        </DataTemplate>
      </ContentControl.Resources>
      <ContentControl.ContentTemplate>
        <DataTemplate>
          <ContentControl Name="cc"
                          Content="{Binding}"
                          ContentTemplate="{StaticResource PinkTemplate}" />
          <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding}" Value="True">
              <Setter TargetName="cc" 
                      Property="ContentTemplate"
                      Value="{StaticResource LimeTemplate}" />
            </DataTrigger>
          </DataTemplate.Triggers>
        </DataTemplate>
      </ContentControl.ContentTemplate>
    </ContentControl>
    

    Note that my DataTemplate is another ContentControl, which allows my DataTemplate.Triggers to operate on the ContentTemplate of that (nested) ContentControl.