Search code examples
wpfdatatriggerhierarchicaldatatemplate

How to change HierarchicalDataTemplate?


How can I change HierarchicalDataTemplate by DataTrigger in my TreeView?

<TreeView Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"
          ItemsSource="{Binding Nodes}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="True" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
            <HierarchicalDataTemplate.Triggers>
                <DataTrigger Binding="{Binding Type}" Value="group">
                    <Setter Property="Content">
                        <Setter.Value>
                            <TextBlock Text="{Binding Title}" />
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding Type}" Value="page">
                    <Setter Property="Content">
                        <Setter.Value>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Page.Name}" />
                                <TextBlock Text="{Binding Page.Format}" />
                            </StackPanel>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </HierarchicalDataTemplate.Triggers>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

In ItemSource of TreeView i put list of Node objects:

public class Node
{
    public string Title { get; set; }
    public Page Page { get; set; }
    public string Type { get; set; }
    public List<Node> Nodes { get; set; } = new List<Node>();
}

And this is the result:

And result

What am I doing wrong?


Solution

  • In WPF, the "correct" way to create complex content is with a template.

    I tried the XAML below, and it worked. Where I bind Content="{Binding}" on the inner ContentControl, that just binds the content of the contentcontrol to the DataContext of the parent -- in this case, the Node object.

    <TreeView 
        Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"
        ItemsSource="{Binding Nodes}"
        >
        <TreeView.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Setter Property="IsExpanded" Value="True" />
            </Style>
        </TreeView.ItemContainerStyle>
        
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
                <ContentControl
                    x:Name="PART_ContentControl"
                    Content="{Binding}"
                    />
                <HierarchicalDataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Type}" Value="Group">
                        <Setter Property="ContentTemplate" TargetName="PART_ContentControl">
                            <Setter.Value>
                                <DataTemplate>
                                    <TextBlock Text="{Binding Title}" />
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Type}" Value="Page">
                        <Setter Property="ContentTemplate" TargetName="PART_ContentControl">
                            <Setter.Value>
                                <DataTemplate>
                                    <StackPanel Orientation="Vertical">
                                        <TextBlock Text="{Binding Page.Name}" />
                                        <TextBlock Text="{Binding Page.Format}" />
                                    </StackPanel>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                </HierarchicalDataTemplate.Triggers>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>