Search code examples
wpftreeviewcontroltemplatehierarchicaldatatemplateitemtemplateselector

Both 'ItemTemplate' and 'ItemTemplateSelector' are set; 'ItemTemplateSelector' will be ignored


Following this question, I have another question about TreeView.

What I already have is a TreeViewwith HierarchicalDataTemplate, in which I can change the HierarchicalDataTemplate of level2 (like explained in the question and the answer).

What I want now, is to change the look of the expander of the Treeview. For this, I have defined a ControlTemplate named ctForTreeViewItem, and I use it like this:

<Window.Resources>
    <ControlTemplate x:Key="ctForTreeViewItem"
                     TargetType="{x:Type TreeViewItem}">
        <Expander IsExpanded="True"
                  Background="Grey"
                  BorderBrush="Transparent"
                  Foreground="White"
                  BorderThickness="1,1,1,3">
            <Expander.Header>
                <Border BorderThickness="{TemplateBinding Border.BorderThickness}"
                        Padding="{TemplateBinding Control.Padding}"
                        BorderBrush="{TemplateBinding Border.BorderBrush}"
                        Background="{TemplateBinding Panel.Background}"
                        Name="Bd"
                        SnapsToDevicePixels="True"
                        Grid.Column="1">
                    <ContentPresenter Content="{TemplateBinding HeaderedContentControl.Header}"
                                      ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}"
                                      ContentStringFormat="{TemplateBinding HeaderedItemsControl.HeaderStringFormat}"
                                      ContentSource="Header"
                                      Name="PART_Header"
                                      HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
                                      SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                </Border>
            </Expander.Header>

            <Expander.Content>
                <ItemsPresenter x:Name="ItemsHost" />
            </Expander.Content>

        </Expander>
    </ControlTemplate>

    <DataTemplate x:Key="Level3Template">
        <Border Background="LightBlue">
            <TextBlock Text="Level3"/>
        </Border>
    </DataTemplate>

    <HierarchicalDataTemplate x:Key="Level2RedTemplate"
                          ItemsSource="{Binding Value}"
                          ItemTemplate="{StaticResource Level3Template}">
        <Border Background="Red">
            <TextBlock Text="Level2"/>
        </Border>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="Level2YellowTemplate"
                          ItemsSource="{Binding Value}"
                          ItemTemplate="{StaticResource Level3Template}">
        <Border Background="Yellow">
            <TextBlock Text="Level2"/>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="Level1Template" 
                          ItemsSource="{Binding Value}"
                          ItemTemplateSelector="{StaticResource MySelector}">

        <HierarchicalDataTemplate.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Setter Property="Template"
                        Value="{StaticResource ctForTreeViewItem}" />
            </Style>
        </HierarchicalDataTemplate.ItemContainerStyle>

        <Border Background="Green">
            <TextBlock Text="Level1"/>
        </Border>
    </HierarchicalDataTemplate>
</Window.Resources>

<TreeView Grid.Row="1"
          Name="tv"
          ItemsSource="{Binding Items}"
          ItemTemplate="{StaticResource Level1Template}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="Template"
                    Value="{StaticResource ctForTreeViewItem}" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

This works for Level1 as expected, so on Level 1, I have TreeViewItems with the defined ControlTemplate and the Correct HierarchicalDataTemplate.

However, it doesn't work on Level2, where I have an ItemTemplateSelector. At this position, I get this error: System.Windows.Data Error: 25 : Both 'ItemTemplate' and 'ItemTemplateSelector' are set; 'ItemTemplateSelector' will be ignored.

  • Is there any way, that I can assign a ControlTemplate to the TreeViewItems, while keeping the ItemTemplateSelector? Or even

  • Is there any other way, that I can change the style of the expander of the TreeView?


Solution

  • Your TreeViewItem ControlTemplate is broken. It ignores the data template selector because you explicitly override that by setting ContentTemplate on the ContentPresenter. That's similar to what's causing the (harmless) errors in your debug output stream as well: The level 2 templates inherit an ItemTemplateSelector from their ancestors, in the same way that if you set ItemContainerStyle once on the TreeView, it will be inherited by all children of the treeview unless some intervening child overrides it explicitly. No need to set it more than once. Because the level 2 templates inherit ItemTemplateSelector and override it with a different property, you get an error, but it's harmless.

    I fixed the control template by changing the ContentPresenter for the Header to match the default TreeViewItem control template: I removed the Content, ContentTemplate, and ContentStringFormat attributes. The ContentPresenter has default behavior for all that stuff so you don't need to specify it explicitly.

    <ContentPresenter 
        ContentSource="Header"
        Name="PART_Header"
        HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
        SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" 
        />
    

    The template/template selector errors are harmless but I was able to silence them by setting ItemTemplateSelector explicitly to null on the level 2 hierarchical data templates:

    <HierarchicalDataTemplate 
        x:Key="Level2RedTemplate"
        ItemsSource="{Binding Value}"
        ItemTemplateSelector="{x:Null}"
        ItemTemplate="{StaticResource Level3Template}"
        >
        <Border Background="Red">
            <TextBlock Text="Level2"/>
        </Border>
    </HierarchicalDataTemplate>