Wednesday, March 24, 2010

Individual DataTemplates for Programmatically Populated Silverlight TreeView

Silverlight TreeView can be populated both declaratively and programmatically. In complex scenarios, the latter is preferred. This simple tutorial demonstrates how individual DataTemplates can be selected for newly created items.

Let’s start with creating a business class we will use to create tree items:

public class Person
{
public string Name { get; set; }
public string Surname { get; set; }

public override string ToString()
{
return string.Format( "{0} {1}", Name, Surname );
}
}





Let’s also create the XAML containing a TreeView and two distinct DataTemplates for tree items. Note that both templates contain explicit bindings to model’s properties: first template will render a tree item as text while the second will render it as a button.



In the latter case we’d also like to be able to determine the business entity bound to the button the user clicks.




<UserControl 
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
x:Class="SilverlightTutorial1.MainPage"
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" d:DesignWidth="640" d:DesignHeight="480">
<UserControl.Resources>
<DataTemplate x:Key="TreeViewItemTemplate1">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
<DataTemplate x:Key="TreeViewItemTemplate2">
<Button Content="{Binding}" Tag="{Binding}" Click="Button_Click" />
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<controls:TreeView x:Name="TheTree">

</controls:TreeView>
</Grid>
</UserControl>





Items will be created programmatically and the trick is to set an instance of the business entity as TreeViewItem’s Header and in the same time set TreeViewItem’s HeaderTemplate to point to a DataTemplate, picking one from resources.




public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();

TreeViewItem item = InitNodeFromTemplate1();
InitNodeFromTemplate2(item);
}

private TreeViewItem InitNodeFromTemplate1()
{
TreeViewItem item = new TreeViewItem();

item.Header = new Person() { Name = "John", Surname = "Kowalski" };
item.HeaderTemplate = (DataTemplate)this.Resources["TreeViewItemTemplate1"];

TheTree.Items.Add( item );

return item;
}

private void InitNodeFromTemplate2( TreeViewItem Parent )
{
TreeViewItem item = new TreeViewItem();

item.Header = new Person() { Name = "Tim", Surname = "Malinowski" };
item.HeaderTemplate = (DataTemplate)this.Resources["TreeViewItemTemplate2"];

Parent.Items.Add( item );
}

private void Button_Click( object sender, RoutedEventArgs e )
{
Button b = sender as Button;
Person p = b.Tag as Person;

MessageBox.Show( p.ToString() );
}





Note that the button’s click handler retrieves the business entity from the button’s Tag property and this is possible because of the binding inside the TreeViewItemTemplate2 DataTemplate.



The output of the above example looks like this:







Note that DataTemplates can be created programmatically. This is described in this blog note by Tamir Khason.

3 comments:

Application Security said...

Great Article!! Thanks for sharing...

Anonymous said...

Indeed, thanks for writing this up, saved me from the world of hurt I was thrashing around in.

vincentadell said...

C# populating Kettic TreeView with data