There are many examples of using the Windows Presentation Foundataion (WPF) Tree View that you can find on the Web, however, most of them only show you how to go to two levels. What if you have more than two levels? This is where it’s vital to understand exactly how the Hierarchical Data Templates work. In this article, I’m going to break down how these templates work, so you can really understand what’s going on underneath the hood.

A Hard-Coded WPF Tree View

To start, let’s look at the typical two-level WPF Tree View that has been hard-coded with the values shown in the following code snippet.

<TreeView>
  <TreeViewItem Header="Managers">
    <TextBlock Text="Michael" />
    <TextBlock Text="Paul" />
  </TreeViewItem>
  <TreeViewItem Header="Project Managers">
    <TextBlock Text="John" />
    <TextBlock Text="Tim" />
    <TextBlock Text="David" />
  </TreeViewItem>
</TreeView>

Figure 1 shows you how this Tree View looks when you run the WPF application.

Figure 1: A hard-coded two-level Tree View

Create Hierarchical Classes to Mimic Your Tree View

You don’t want to use hard-coded XAML in your WPF application. You want to retrieve data from a database table or an XML file and build the Tree View dynamically. How and from where you retrieve the data is not important for this article. What’s important is how you structure the classes into which your data will be placed. Just as a Tree View is a hierarchical structure, create a set of classes that is also a hierarchy.

Figure 2 shows the three classes that will be necessary for expressing a hierarchy of Employee Type objects of which each Employee Type object can hold one or more Employee objects.

Figure 2: Three classes are needed to express a three-level Tree View.

The first class you build is the Employee class. This class has a single property called Name. A constructor is created to accept a “name” argument that you can use to set the Name property when you create an Employee object.

public class Employee
{
  public Employee(string name)
  {
    Name = name;
  }
    
  public string Name { get; set; }
}

The EmployeeType class contains two properties. First is a string property, called Description, which holds the name of the employee type, such as “Supervisor” or “Project Manager.” The second property, Employees, is a generic collection property to hold a list of Employee objects that are associated with this particular employee type.

public class EmployeeType
{
  public EmployeeType(string desc)
  {
    Description = desc;
    Employees = new List<Employee>();
  }
    
  public string Description { get; set; }
  public List<Employee> Employees { get; set; }
}

The last class you create is collection class called EmployeeTypes created using the generic List class. This is a collection of EmployeeType objects. In the constructor of the EmployeeTypes collection class, you build the collection of EmployeeType objects and fill each one with Employee objects, as shown in Listing 1. For purposes of this article, I’m using hard-coded data. Feel free to load this collection with the data of your choice.

If you create an instance of the EmployeeTypes class as shown in the following code snippet, you will create the hierarchy of employee types and employees shown in Figure 3.

EmployeeTypes types = new EmployeeTypes();

If you compare Figure 1 and Figure 3, you can see that the two structures are very similar. At the top, you have the employee types (Manager and Project Managers), and the next level under each employee type is a collection of employee objects (Tim, John, David). Matching your class hierarchy to the Tree View display is your first step in ensuring that you can display your data in a Tree View format.

Figure 3: A hierarchical data structure of Employee Types containing a collection of Employee objects

Create Your Data and Data Templates using XAML

When using XAML, you don’t need to create an instance of the EmployeeTypes class in C# or Visual Basic code. Instead, you use XAML to create the instance of the EmployeeTypes class as shown in line 12 of Figure 4. Provide your instance of EmployeeTypes with a name using the “x:Key” attribute, in this example, theData. Notice in line 28 of Figure 4 that the ItemsSource of the Tree View control is using the static resource with the key of theData as the source of data for the Tree View.

Figure 4: You need to start from the bottom up when laying out your templates for a Tree View

With the ItemsSource property of the Tree View control set to the collection of EmployeeType objects, you are now ready to start building the hierarchy of XAML DataTemplate objects. What’s important here is that the last level displayed in your Tree View is expressed in a <DataTemplate> listed first in your Resources section, as shown in lines 14-16 of Figure 4. Notice that the TextBlock control within the <DataTemplate> is bound to the Name property of your Employee class. The employee name is indeed what shows up in the last level of the Tree View shown in Figure 1.

As this is just a two-level Tree View, you only need a single <HierarchicalDataTemplate> resource listed after the <DataTemplate> resource. Set the ItemTemplate property in your Hierarchical Data Template to the key name of the Data Template. Set the ItemsSource property to the collection of objects that contain the path of the data expressed in the Data Template. In this case, the ItemsSource uses the Employees property as the collection of Employee objects. Each Employee object has a Name property that’s used in the Data Template to display the name of the employee in the Tree View.

In the <HierarchicalDataTemplate> resource, you use a TextBlock to display the appropriate EmployeeType property in the first level of the Tree View. The TextBlock control in line 20 of Figure 4 uses the Description property of the EmployeeType class.

The Tree View control has its ItemTemplate property set to the key of the last <HierarchicalDataTemplate> resource in your Resources section. The order of the XAML you create for a Tree View is important. The lowest level you wish to display within your Tree View control needs to be listed first in your Resources section. The reason for this should be fairly obvious: Each resource as you work down through the Resources section needs to reference an “x:Key” of another XAML element. XAML can only reference keys that have been previously defined.

Three Levels in a Tree View

Now let’s expand upon the two-level Tree View and use three levels in the Tree View. The Tree View shown in Figure 5 again uses the EmployeeTypes at the top of the tree, followed by a small set of employees that themselves manage employees. To make this Tree View display, modify the Employee class to contain a collection of Employee objects (named ManagedEmployees) as shown in the following code snippet.

public class Employee
{
  public Employee(string name)
  {
    Name = name;
    ManagedEmployees = new List<Employee>();
  }
    
  public string Name { get; set; }
  public List<Employee> ManagedEmployees { get; set; }
}

Figure 5: A Tree View control can have as many levels as you want; it only requires you to build the appropriate templates in WPF.

Next, you need to modify the constructor of the EmployeeTypes class to create a list of managed employees within each Employee object. Listing 2 shows the new code where, after creating an Employee object, you add another employee to the ManagedEmployees property.

Now that you have your three-level structure built into your classes, you are ready to hook up this three-level structure to your Tree View. As you might expect, you are going to add another <HierachicalDataTemplate> in between the old <HierachicalDataTemplate> and the <DataTemplate> shown in Figure 4. Of course, one of the x:Key attributes will have to change in order to accommodate this new template.

Figure 6 shows the complete XAML needed to hook up your three-level Tree View. You can see in the XAML that there are now two Hierarchical Data Templates and one Data Template. Again, you list the Data Template first, because that’s the lowest level in your Tree View. The next Hierarchical Data Template listed is the next level up from the lowest level, and finally you have a Hierarchical Data Template for the first level in your tree. As mentioned before, you always work your way from the bottom up when creating your Tree View hierarchy. XAML is processed from the top down, so any attempt to reference an XAML x:Key that’s below where you’re referencing it from results in a runtime error.

Figure 6: For three levels in a Tree View you need two Hierarchical Data Templates and one Data Template.

Each Hierarchical Data Template uses the x:Key name of the previous template as its ItemTemplate. The ItemsSource of each Hierarchical Data Template is used to feed the data to the previous template. This is probably the most confusing part about working with the Tree View control. You expect the content of the current Hierarchical Data Template to use the properties set in the ItemsSource property of that template. But you need to look to the template lower down in the XAML to see the source of the data, as shown in Figure 7.

Figure 7: The properties you use within the Content of a template come from the ItemsSource of the next template in the resources section.

Summary

Understanding how to put together your hierarchy in a Tree View is simple once you understand that you need to work from the bottom up. Start with the bottom node in your Tree View and determine what that will look like and where the data will come from. Then build the next Hierarchical Data Template to feed the data to the previous template you created. You keep doing this for each level in your Tree View until you get to the last level. The data for that last Hierarchical Data Template comes from the ItemsSource in the Tree View itself. Structure your data classes to mimic the hierarchical structure of your Tree View, and displaying a Tree View becomes quite simple.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select PDSA Articles, then select Code Magazine: WPF TreeView with Multiple Levels from the drop-down list.