#1,217 – Using Multiple HierarchicalDataTemplates in a TreeView

I showed last time how to use a HierarchicalDataTemplate as the ItemTemplate for a TreeView. This allowed us to specify the look and feel of each node in the tree and also dictated how the main data item would be traversed to generate the tree.

If you have some hierarchical data in which the items are not all of the same type, you can specify more than one HierarchicalDataTemplate for the TreeView, based on the underlying type of each node.

Let’s assume that we have both a Breed and a Dog class. Breed objects contain information about a breed and in turn have a Dogs property that is a list of individual dogs of that breed.

In the example below, we have a TreeView whose ItemsSource is bound to a list of breeds. We then include a template to use for each Breed item and a different template to use for each Dog item in the tree. We also indicate that the tree should be expanded by looking at the Dogs property in each breed instance.

        <TreeView Grid.Row="0" Margin="5" ItemsSource="{Binding Breeds}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type loc:Breed}" ItemsSource="{Binding Dogs}">
                    <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                        <TextBlock Text="Breed:"/>
                        <TextBlock Margin="5,0,0,0" FontWeight="Bold" Text="{Binding Name}"/>
                    </StackPanel>
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate DataType="{x:Type loc:Dog}">
                    <StackPanel Orientation="Horizontal" Margin="0,2,0,0">
                        <TextBlock Text="{Binding}"/>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>

Note that we specify a DataType for each HierarchicalDataTemplate. As the tree is constructed, the appropriate template will be used, based on whether a node is a breed or a dog.

Below, we can see how this will look at runtime. Breed nodes show the breed’s name. Dog nodes show the dog’s name and age. We just have a TextBlock bound to the Dog instance as a whole, which causes the dog’s ToString method to get invoked. In our case, we’ve overridden ToString to display the dog’s name and age.

Advertisements