2. Add a reference to the Silverlight Controls assembly (Microsoft.Windows.Controls.dll) which can be downloaded at http://codeplex.com/Silverlight.
3. Look under "Custom Controls" In the Blend Asset Library.
4. Add a TreeView to the Page.
And here's the XAML Blend generated for us:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SilverlightControlsNovember2008.TreeViewPage"
d:DesignWidth="640" d:DesignHeight="480"
xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
<Grid x:Name="LayoutRoot" Background="#FFFFFFFF">
<controls:TreeView Margin="79,98,0,0" VerticalAlignment="Top" Height="200" Width="120" HorizontalAlignment="Left"/>
</Grid>
</UserControl>
Manually Adding New Textual TreeViewItems to a TreeView
Let’s add some TreeViewItems to our TreeView that will reflect a family’s genealogy tree. like so:
We’ll right click on TreeView –> Add TreeViewItem.
And we can see that we indeed got a new TreeViewItem nested under or TreeView:

Next, we’ll go to the TreeViewItem’s properties and set Header to “Sally” and IsExpanded to true.
Here’s the XAML blend generated for us up until now:
<controls:TreeView Height="200" Width="120">
<controls:TreeViewItem IsExpanded="True" Header="Sally"/>
</controls:TreeView>
Now we’d like to add “John” as a child TreeViewItem of “Sally”.
We’ll Right click on “Sally” TreeViewItem –> Add TreeViewItem.
And we got another nested note inside the previous TreeViewItem:
We’ll edit it’s Header to “John” and we’ll keep IsExpanded to false, because it has no nested nodes.
We’ll keep it up until we get the following TreeView:
Let’s run our sample:
And we can start collapsing, expanding & Selecting TreeViewItems:
(In the above sample, Greg is collapsed, and John is selected)
And here’s the XAML Blend generated for us:
<controls:TreeView Height="200" Width="120">
<controls:TreeViewItem IsExpanded="True" Header="Sally">
<controls:TreeViewItem Header="John"/>
<controls:TreeViewItem Header="Greg" IsExpanded="True">
<controls:TreeViewItem Header="Linda"/>
<controls:TreeViewItem Header="Darren"/>
</controls:TreeViewItem>
<controls:TreeViewItem Header="Allice" IsExpanded="True">
<controls:TreeViewItem Header="Neil"/>
</controls:TreeViewItem>
</controls:TreeViewItem>
</controls:TreeView>
Editing the TreeViewItem’s Header property in Visual Studio XAML Editor
Now it’s time to uncover the horrible truth – Sally and her children are all aliens. The green “blip blip” kind.
This is how our TreeView should look like when we’re done:
Blend currently does not support editing the Header property in a visual way. So we’ll open up Visual Studio’s XAML editor for that.
Right click on “TreeViewPage.xaml” (which is our page) in the Blend project tab –> Edit In Visual Studio.
And in a few second we’ll see this screen:
We’ll start off by changing the first TreeViewItem:
<controls:TreeViewItem IsExpanded="True" Header="Sally">
First, we’ll expand the Header property to allow XAML content:
<controls:TreeViewItem IsExpanded="True">
<controls:TreeViewItem.Header></controls:TreeViewItem.Header>
We’ll fill in the “Sally” content:
<controls:TreeViewItem IsExpanded="True">
<controls:TreeViewItem.Header>
<TextBlock Text="Sally" />
</controls:TreeViewItem.Header>
And our TreeView still looks exactly the same:
Now we’d like to add the image of our Alien, but the Header can only contain a single element.
So we’ll group the <Image> and the <TextBlock> in a horizontal <StackPanel>.
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Sally" />
</StackPanel>
</controls:TreeViewItem.Header>
Now that we have a container in the Header, we’ll add the <Image> tag.
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien1.png" />
<TextBlock Text="Sally" />
</StackPanel>
</controls:TreeViewItem.Header>
In our Visual Studio preview windows we can see the following image:
Well, The text is too small for our picture. So let’s change the FontSize for the TreeView to 22.
<controls:TreeView FontSize="22" Height="200" Width="120">
We can see the Horizontal and Vertical Scrollbars appear because now our TreeViewItems are bigger than the TreeView. We’ll change the TreeView Width & Height accordingly.
<controls:TreeView FontSize="22" Height="350" Width="250">
Now our TreeView looks much better:
here’s our XAML up until now:
<controls:TreeView FontSize="22" Height="350" Width="250" Margin="84,101,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<controls:TreeViewItem IsExpanded="True">
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien1.png" />
<TextBlock Text="Sally" />
</StackPanel>
</controls:TreeViewItem.Header>
<controls:TreeViewItem Header="John"/>
<controls:TreeViewItem Header="Greg" IsExpanded="True">
<controls:TreeViewItem Header="Linda"/>
<controls:TreeViewItem Header="Darren"/>
</controls:TreeViewItem>
<controls:TreeViewItem Header="Allice" IsExpanded="True">
<controls:TreeViewItem Header="Neil"/>
</controls:TreeViewItem>
</controls:TreeViewItem>
</controls:TreeView>
We’ll repeat the process of editing an Image for the other 6 TreeViewItems. Than we’ll run our application.
here’s the XAML we wrote:
<controls:TreeView FontSize="22" Height="350" Width="250" Margin="84,101,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<controls:TreeViewItem IsExpanded="True">
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien1.png" />
<TextBlock Text="Sally" />
</StackPanel>
</controls:TreeViewItem.Header>
<controls:TreeViewItem>
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien2.png" />
<TextBlock Text="John" />
</StackPanel>
</controls:TreeViewItem.Header>
</controls:TreeViewItem>
<controls:TreeViewItem IsExpanded="True">
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien3.png" />
<TextBlock Text="Greg" />
</StackPanel>
</controls:TreeViewItem.Header>
<controls:TreeViewItem>
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien4.png" />
<TextBlock Text="Linda" />
</StackPanel>
</controls:TreeViewItem.Header>
</controls:TreeViewItem>
<controls:TreeViewItem>
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien5.png" />
<TextBlock Text="Darren" />
</StackPanel>
</controls:TreeViewItem.Header>
</controls:TreeViewItem>
</controls:TreeViewItem>
<controls:TreeViewItem IsExpanded="True">
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien6.png" />
<TextBlock Text="Allice" />
</StackPanel>
</controls:TreeViewItem.Header>
<controls:TreeViewItem>
<controls:TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Alien7.png" />
<TextBlock Text="Neil" />
</StackPanel>
</controls:TreeViewItem.Header>
</controls:TreeViewItem>
</controls:TreeViewItem>
</controls:TreeViewItem>
</controls:TreeView>
We can definitely see that we’ve did some copy & paste here. Next we’ll see how we can use DataBinding to remove this repeatable code.
Specifying a DataTemplate as the TreeView’s ItemTemplate
Well, now we’d like to remove that duplicated code by using some DataBinding.
We’ve got this Alien class:
public class Alien
{
public Alien(string name, string pictureUrl)
{
Name = name;
Picture = new BitmapImage(new Uri(pictureUrl, UriKind.Relative));
}
public string Name { get; set; }
public BitmapImage Picture { get; set; }
}
Pretty simple, we’ve got a Name property, and a Picture property the we’re settings with way Silverlight uses for Image.Source databinding.
We’ll jump back to Blend.
And clear all the Items from the TreeViewItem by selecting the first TreeViewItem and deleting it.
Now that we have an empty TreeView, we’d like to set a x:Name so we can setup the TreeView‘s DataContext from our Code-behind.
We’ll set the TreeView ItemSource to run on a collection of aliens.
void TreeViewPage_Loaded(object sender, RoutedEventArgs e)
{
trvAliens.ItemsSource = new List<Alien>()
{
new Alien("Sally", "Alien1.png"),
new Alien("John", "Alien2.png"),
new Alien("Greg", "Alien3.png"),
new Alien("Linda", "Alien4.png"),
new Alien("Darren", "Alien5.png"),
new Alien("Alice", "Alien6.png"),
new Alien("Neil", "Alien7.png"),
};
}
Now, we can finally get down to business – changing the TreeView’s ItemTemplate.
Right Click on TreeView –> Edit Other Templates –> Edit Generated Items (ItemTemplate) –> Create Empty.
We’ll call our new Template AlienTemplate.
We can see that we have an empty DataTemplate:
First, we’ll Change the Grid to a Horizontal StackPanel.
Right Click Grid –> Change Layout Type –> StackPanel.
Next we’ll add an Image control.
And we’ll want to DataBind it’s Source Property to Alien.Picture property.
Click Advanced Property options next to Source.
Select “Custom Expression”.
And put in “{Binding Picture}”.
Next we’ll add a TextBlock and Bind it’s Text property to “{Binding Name}”.
-->
–>
-->
Let’s run this sample:
Here’s the XAML Blend Generated for our TreeView:
<controls:TreeView FontSize="22" Height="350" Width="250" x:Name="trvAliens" ItemTemplate="{StaticResource AlienTemplate}"/>
Here’s the XAML Blend generated for our ItemTemplate:
<UserControl.Resources>
<DataTemplate x:Key="AlienTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
Here’s our Code-behind:
void TreeViewPage_Loaded(object sender, RoutedEventArgs e)
{
trvAliens.ItemsSource = new List<Alien>()
{
new Alien("Sally", "Alien1.png"),
new Alien("John", "Alien2.png"),
new Alien("Greg", "Alien3.png"),
new Alien("Linda", "Alien4.png"),
new Alien("Darren", "Alien5.png"),
new Alien("Alice", "Alien6.png"),
new Alien("Neil", "Alien7.png"),
};
}
And our current Alien Class:
public class Alien
{
public Alien(string name, string pictureUrl)
{
Name = name;
Picture = new BitmapImage(new Uri(pictureUrl, UriKind.Relative));
}
public string Name { get; set; }
public BitmapImage Picture { get; set; }
}
Specifying a HierarchalDataTemplate as a TreeView’s ItemTemplate in Visual Studio XAML Editor
In case you haven’t noticed, our current TreeView is pretty flat. It only has 1 level. And we’d like to get a similar TreeView to the one we previously had, with Nested TreeViewItems.
We’ll start by changing our CLR Alien Type:
public class Alien
{
public Alien(string name, string pictureUrl, params Alien[] children)
{
Name = name;
Picture = new BitmapImage(new Uri(pictureUrl, UriKind.Relative));
Children = children;
}
public string Name { get; set; }
public BitmapImage Picture { get; set; }
public Alien[] Children { get; set; }
}
All we did is add a property that is collection of Aliens that are the Children of that Alien.
Now that we’ve got a Hierarchical Alien class, we’ll change our code behind to use it:
void TreeViewPage_Loaded(object sender, RoutedEventArgs e)
{
trvAliens.ItemsSource = new List<Alien>()
{
new Alien("Sally", "Alien1.png",
new Alien("John", "Alien2.png"),
new Alien("Greg", "Alien3.png",
new Alien("Linda", "Alien4.png"),
new Alien("Darren", "Alien5.png")
),
new Alien("Alice", "Alien6.png",
new Alien("Neil", "Alien7.png")
)
)
};
}
The next part of changing our ItemTemplate is not supported by Blend. so we’re back at editing XAML in Visual Studio XAML Editor.
This is our current DataTemplate:
<DataTemplate x:Key="AlienTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
Let’s change it to a HierarchicalDataTemplateL:
<controls:HierarchicalDataTemplate x:Key="AlienTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</controls:HierarchicalDataTemplate>
And we’ll need to point to our new Hierarchical CLR property – Children.
We’ll do that by Setting HierarchicalDataTemplate.ItemsSource to “{Binding Children}”.
<controls:HierarchicalDataTemplate x:Key="AlienTemplate" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</controls:HierarchicalDataTemplate>
Let’s run the sample:
Here’s our XAML code for the TreeView (hasn’t changed during this sample):
<controls:TreeView FontSize="22" Height="350" Width="250" x:Name="trvAliens" ItemTemplate="{StaticResource AlienTemplate}"/>
Here’s our updated ItemTemplate:
<UserControl.Resources>
<controls:HierarchicalDataTemplate x:Key="AlienTemplate" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</controls:HierarchicalDataTemplate>
</UserControl.Resources>
Here’s our updated Alien class:
public class Alien
{
public Alien(string name, string pictureUrl, params Alien[] children)
{
Name = name;
Picture = new BitmapImage(new Uri(pictureUrl, UriKind.Relative));
Children = children;
}
public string Name { get; set; }
public BitmapImage Picture { get; set; }
public Alien[] Children { get; set; }
}
And our updated Code-behind:
void TreeViewPage_Loaded(object sender, RoutedEventArgs e)
{
trvAliens.ItemsSource = new List<Alien>()
{
new Alien("Sally", "Alien1.png",
new Alien("John", "Alien2.png"),
new Alien("Greg", "Alien3.png",
new Alien("Linda", "Alien4.png"),
new Alien("Darren", "Alien5.png")
),
new Alien("Alice", "Alien6.png",
new Alien("Neil", "Alien7.png")
)
)
};
}
Syncing a TreeView SelectedItem with an External Control
We’d like to have a big bold TextBlock on top of our page which says “Selected Alien: <Name of Alien>”. like so:
So, first, we’ll add a big TextBlock saying “Selected Alien:” in big bold letter.
And another empty TextBlock called “txtSelectedAlienName” with the same font properties.
Next we’d like to register to the SelectedItemChanged event.
public TreeViewPage()
{
// Required to initialize variables
InitializeComponent();
this.Loaded += new RoutedEventHandler(TreeViewPage_Loaded);
trvAliens.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(trvAliens_SelectedItemChanged);
}
void trvAliens_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
}
Here are the EventArgs for this event:
We’ll convert e.NewValue to Alien CLR type, and use it’s Name to fill our TextBlock.
void trvAliens_SelectedItemChanged(object sender,
RoutedPropertyChangedEventArgs<object> e)
{
txtSelectedAlienName.Text = ((Alien) e.NewValue).Name;
}
Let’s run our sample:
And if we select “John”:
Here’s our updated XAML:
<controls:TreeView FontSize="22" Height="350" Width="250" Margin="84,101,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" x:Name="trvAliens" ItemTemplate="{StaticResource AlienTemplate}"/>
<TextBlock Height="46" Margin="22,38,0,0" VerticalAlignment="Top" FontWeight="Bold" TextWrapping="Wrap" Width="257" HorizontalAlignment="Left"><Run FontSize="30" Text="Selected Alien:"/></TextBlock>
<TextBlock Height="46" Margin="279,38,204,0" VerticalAlignment="Top" TextWrapping="Wrap" FontSize="30" FontWeight="Bold" FontFamily="Portable User Interface" TextDecorations="Underline" x:Name="txtSelectedAlienName"/>
And our updated code-behind:
public TreeViewPage()
{
// Required to initialize variables
InitializeComponent();
this.Loaded += new RoutedEventHandler(TreeViewPage_Loaded);
trvAliens.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(trvAliens_SelectedItemChanged);
}
void trvAliens_SelectedItemChanged(object sender,
RoutedPropertyChangedEventArgs<object> e)
{
txtSelectedAlienName.Text = ((Alien)e.NewValue).Name;
}
Using the TreeView SelectedValue and SelectedValueMember
Let’s refactor our previous code sample so instead of using e.NewValue it would use the TreeView’s SelectedValue.
SelectedValue reflects a specific property on the current SelectedItem based on SelectedValuePath. complicated? not really.
this handler:
void trvAliens_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
txtSelectedAlienName.Text = ((Alien)e.NewValue).Name;
}
is equivalent to this code:
void trvAliens_SelectedItemChanged(object sender,
RoutedPropertyChangedEventArgs<object> e)
{
txtSelectedAlienName.Text = ((Alien)trvAliens.SelectedValue).Name;
}
in stead of asking the what’s the new selected Item, we can just ask the TreeView what’s the currently selected item.
By default, SelectedValue is the CLR type behind the currently selected TreeViewItem.
Instead of converting our SelectedValue back to Alien and getting Name, we can set SelectedValuePath to “Name”.
And now with this change, SelectedValue isn’t Alien anymore, but the value of Alien.Name.
so, we can re-write our handler to:
void trvAliens_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
txtSelectedAlienName.Text = trvAliens.SelectedValue.ToString();
}
And we get the exact same UI:
Here’s the XAML Blend generated for us:
<controls:TreeView FontSize="22" Height="350" Width="250" x:Name="trvAliens" ItemTemplate="{StaticResource AlienTemplate}" SelectedValuePath="Name"/>
And here’s our updated Event Handler:
void trvAliens_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
txtSelectedAlienName.Text = trvAliens.SelectedValue.ToString();
}
Changing Visual States – Changing the Collapsed and Extended Visual States
Looking at this last Print screen a bit more closely we can see It uses to types of Icons:
- Expanded Icon
- Collapsed Icon
We’d like to change those to:
- Collapsed Icon
- Expanded Icon
In order to do that, we’ll have to edit the Template of the TreeViewItem generated by the TreeView.
To do that, we’ll change the TreeView ItemContainerStyle that gets applied on to each generated TreeViewItem.
We’ll select the TreeView, go to “Object –> Edit Other Styles –> Edit ItemContainerStyle –> Edit Copy”.
And we’ll call the new Style “AlienItemStyle”.
Next, we’ll need to drill into editing the template for the TreeViewItems.
We’ll do that through “Edit Template –> Edit Controls Parts (Template) –> Edit Template”.
Here’s what we see:
There are a few VisualStateManager states here. And we’ve got a template that has a few visual elements in it.
One of those is the Expander button.
In order to change the TreeViewItem Icons we’ll need to edit the Template for the ExpanderButotn.
Right Click on the ExpanderButton –> Edit Template –> Edit Template.
And here’s what we see:
Apparently, the TreeViewItem ExpanderButton has two visuals: “CheckedVisual”
and “UncheckedVisual”
.
We’ll need to replace those with our new Visuals.
First, I’ll draw a whole ellipse.
And on top of it I’ll draw a rectangle.
I’ll select the Ellipse with the Rectangle. Right Click –> Combine –> Subtract.
And we’ll get this path:
I’ll repeat the process and we’ll also get this path:
Now, In XAML we’ll cut & paste the names of “CheckedVisual” and “UncheckedVisual” to these new elements.

becomes
Next, we’ll delete the old CheckVisual and UncheckedVisual and place our new ones into the correct position.
Now, one last thing we have to change before this runs, is making sure the “UncheckedVisual” is hidden during the “Checked” state.
We’ll go the the “Checked” state.
Select the “UncheckedVisual” and set it’s opacity to 0.
Now if we run our sample:
Here’s the XAML Blend generated for our ListBox:
<controls:TreeView FontSize="22" :Name="trvAliens" ItemTemplate="{StaticResource AlienTemplate}" SelectedValuePath="Name" ItemContainerStyle="{StaticResource AlienItemStyle}" />
Here’s the the Style that was generated for us:
(it’s quite verbose, so the important parts are highlighted)
<Style x:Key="AlienItemStyle" TargetType="controls:TreeViewItem">
<Setter Property="IsTabStop" Value="True"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Cursor" Value="Arrow"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:TreeViewItem">
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="15"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualState x:Name="Normal"/>
<vsm:VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Header" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="#FF999999"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
<vsm:VisualStateGroup x:Name="SelectionStates">
<vsm:VisualState x:Name="Unselected"/>
<vsm:VisualState x:Name="Selected">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="select" Storyboard.TargetProperty="Opacity" To=".75"/>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="SelectedInactive">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="inactive" Storyboard.TargetProperty="Opacity" To=".2"/>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
<vsm:VisualStateGroup x:Name="HasItemsStates">
<vsm:VisualState x:Name="HasItems"/>
<vsm:VisualState x:Name="NoItems">
<Storyboard>