After creating the TreeView in XAML and code, let us bind the TreeView to a collection.
We create a list of strings and set it as DataContext to TreeView:
List<string> items = new List<string>() {"Apple","Oracle","IBM","Microsoft" };
this.DataContext = items;
XAML:
<TreeView Margin="10,10" DockPanel.Dock="Right" Name="tvList" ItemsSource="{Binding}">
</TreeView>
Result is:
This is working like a ListBox, what we need to use is hierarchical data. Let’s create the classes which we will use in binding.
Class Category:
public class Category
{
public string Name
{ get; set; }
public List<string> ItemList
{ get; set; }
}
In the Window code-behind - we create two categories, add them to a list and set the list as the DataContext:
Category c1 = new Category { Name = "Software Companies", ItemList = new List<String>() { "Microsoft", "Oracle", } };
Category c2 = new Category { Name = "Hardware Companies", ItemList = new List<String>() { "Intel", "AMD", } };
List<Category> categories = new List<Category>();
categories.Add(c1);
categories.Add(c2);
tv.DataContext = categories;
XAML:
<Window x:Class="TreeView1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Tree Example" Height="350" Width="525">
<Grid>
<TreeView Name="tv" ItemsSource="{Binding}">
</TreeView>
</Grid>
</Window>
This is what we get:
(Screenshots from XP look ugly, compared to Vista)
As with other list controls, TreeView also uses the default ToString() to show the data. Next, we use an ItemTemplate to show the relevant data.
Updated XAML:
<TreeView Name="tv" ItemsSource="{Binding}">
<TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Output:
Well ok, so now we do get the Category name but what about the items we added in these categories? Let’s update the DataTemplate and use the ItemList property of the class Category:
<TreeView Name="tv" ItemsSource="{Binding}">
<TreeView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="BurlyWood" BorderThickness="2">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Name}" />
<ListBox ItemsSource="{Binding Path=ItemList}"></ListBox>
</StackPanel>
</Border>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Result:
We see the items in each Category, but this is not what we expect from a TreeView. What about the ‘+’ signs? To show them, we need to use a different kind of ItemTemplate – HierarchicalDataTemplate.
The HierarchicalDataTemplate needs two things:
- it needs to know how to display the item data (which is just like a DataTemplate) and
- the Binding path of its children and the template to use to show them
Step 1> Define how the template shows its own data:
<TreeView Name="tv" ItemsSource="{Binding}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate>
<Border BorderBrush="BurlyWood" BorderThickness="2">
<TextBlock Text="{Binding Path=Name}" />
</Border>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Step 2> We add the binding path of its children and their template:
<TreeView Name="tv" ItemsSource="{Binding}">
<TreeView.Resources>
<DataTemplate x:Key="childrenDataTemplate">
<TextBlock Text="{Binding}" />
</DataTemplate>
</TreeView.Resources>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=ItemList}" ItemTemplate="{StaticResource ResourceKey=childrenDataTemplate}">
<Border BorderBrush="BurlyWood" BorderThickness="2">
<TextBlock Text="{Binding Path=Name}" />
</Border>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
You will notice we used HierarchicalDataTemplate for the first level (where we just show the category name), for the second level (showing the items in the category) we use the DataTemplate. When we are sure that the data is the last level in the hierarchy, we use the DataTemplate.