Bookmark and Share Share...    Subscribe to this feed Feed   About Christian Moser  


Data Templates

Introduction

Data Template are a similar concept as Control Templates. They give you a very flexible and powerful solution to replace the visual appearance of a data item in a control like ListBox, ComboBox or ListView. In my opinion this is one of the key success factory of WPF.

If you don't specify a data template, WPF takes the default template that is just a TextBlock. If you bind complex objects to the control, it just calls ToString() on it. Within a DataTemplate, the DataContext is set the data object. So you can easily bind against the data context to display various members of your data object

DataTemplates in Action: Building a simple PropertyGrid

Whereas it was really hard to display complex data in a ListBox with WinForms, its super easy with WPF. The following example shows a ListBox with a list of DependencyPropertyInfo instances bound to it. Without a DataTemplate you just see the result of calling ToString() on the object. With the data template we see the name of the property and a TextBox that even allows us to edit the value.




 
<!-- Without DataTemplate -->
<ListBox ItemsSource="{Binding}" /> 
 
<!-- With DataTemplate -->
<ListBox ItemsSource="{Binding}" BorderBrush="Transparent" 
         Grid.IsSharedSizeScope="True"
         HorizontalContentAlignment="Stretch">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Margin="4">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Key" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding Name}" FontWeight="Bold"  />
                <TextBox Grid.Column="1" Text="{Binding Value }" />
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
 

How to use a DataTemplateSelector to switch the Template depending on the data

Our property grid looks nice so far, but it would be much more usable if we could switch the editor depending on the type of the property.

The simplest way to do this is to use a DataTemplateSelector. The DataTemplateSelector has a single method to override: SelectTemplate(object item, DependencyObject container). In this method we decide on the provided item which DataTemplate to choose.

The following exmple shows an DataTemplateSelector that decides between tree data templates:

 
public class PropertyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultnDataTemplate { get; set; }
    public DataTemplate BooleanDataTemplate { get; set; }
    public DataTemplate EnumDataTemplate { get; set; }
 
    public override DataTemplate SelectTemplate(object item, 
               DependencyObject container)
    {
        DependencyPropertyInfo dpi = item as DependencyPropertyInfo;
        if (dpi.PropertyType == typeof(bool))
        {
            return BooleanDataTemplate;
        }
        if (dpi.PropertyType.IsEnum)
        {
            return EnumDataTemplate;
        }
 
        return DefaultnDataTemplate;
    }
}
 
 
 
<Window x:Class="DataTemplates.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:l="clr-namespace:DataTemplates"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
 
    <Window.Resources>
 
        <!-- Default DataTemplate -->
        <DataTemplate x:Key="DefaultDataTemplate">
           ...
        </DataTemplate>
 
        <!-- DataTemplate for Booleans -->
        <DataTemplate x:Key="BooleanDataTemplate">
           ...
        </DataTemplate>
 
        <!-- DataTemplate for Enums -->
        <DataTemplate x:Key="EnumDataTemplate">
            ...
        </DataTemplate>
 
        <!-- DataTemplate Selector -->
        <l:PropertyDataTemplateSelector x:Key="templateSelector"
              DefaultnDataTemplate="{StaticResource DefaultDataTemplate}"
              BooleanDataTemplate="{StaticResource BooleanDataTemplate}" 
              EnumDataTemplate="{StaticResource EnumDataTemplate}"/>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding}" Grid.IsSharedSizeScope="True" 
                 HorizontalContentAlignment="Stretch" 
                 ItemTemplateSelector="{StaticResource templateSelector}"/>
    </Grid>
</Window>
 
 

How to react to IsSelected in the DataTemplate

If you want to change the appearance of a ListBoxItem when it is selected, you have to bind the IsSelected property of the ListBoxItem. But this is a bit tricky, you have to use a relative source with FindAcestor to navigate up the visual tree until you reach the ListBoxItem.

 
<DataTemplate x:Key="DefaultDataTemplate">
    <Border x:Name="border" Height="50">
        ...
    </Border>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding RelativeSource=
            {RelativeSource Mode=FindAncestor, AncestorType=
                {x:Type ListBoxItem}},Path=IsSelected}" Value="True">
            <Setter TargetName="border" Property="Height" Value="100"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>
 
 




Last modified: 2009-10-08 16:50:58
Copyright (c) by Christian Moser, 2011.

 Comments on this article

Show all comments
Stephen
Commented on 15.December 2009
I think I just decided to learn WPF...
sathya
Commented on 11.February 2010
Hi Christian,
Thank you very much, i got very good basics of WPF, it is really helpfull, i really appreciate your work.Thank you, could you give me guideline how to study WCF bascis, you can send to my mail id sathyajan1@gmail.com. thank you again, i appreciate your work.
Yadav
Commented on 11.March 2010
Very helpful article and I would further appreciate if you give the UI prinout before and after the application of the template. Thank you.
ward
Commented on 20.April 2010
how can i use TreeView control to show SQL-database data in hierarchical view using c sharp.. please help me here because am working on windows from application project . iit's my graduation project.
Confused
Commented on 21.June 2010
This is a poor example. Where is the code behind? Where is the binding? What is this magic data you are adding to the list view?
Confused
Commented on 22.June 2010
This is a poor example. Where is the code behind? Where is the binding? What is this magic data you are adding to the list view?
Confused
Commented on 22.June 2010
This is a poor example. Where is the code behind? Where is the binding? What is this magic data you are adding to the list view?
tim
Commented on 28.June 2010
WOW
danielwu
Commented on 23.July 2010
Mr Confused,

Before you make conclusion, you'd better finish the whole article and then you will find sample solution for download in the end...
Shankarnag
Commented on 24.August 2010
Its really very good information about data templates.
Nikola
Commented on 1.October 2010
Great article, just what I was looking for. Great web site.
Bala
Commented on 9.November 2010
Nice
Hemanath
Commented on 9.November 2010
Worst discussion...lost interest in WPF
Bala
Commented on 9.November 2010
No Hemanath...It is not like that...It is really worth reading...WPF rocks...
Salem5
Commented on 27.November 2010
Thank you, this really saved me a lot of time plowing though Hubers WPF Handbook. It is a worthy read, but I need a few results now.
KMC
Commented on 15.December 2010
I downloaded the sample and all it has it a bunch of checkboxes and textbox, i don't see any datatemplaing in the working...did you upload the wrote source codes?
Jamie
Commented on 10.February 2011
Wow, I worked for a very long time on how to put together a dynamic property editor, and you make it look so easy. The key was Grid.IsSharedSizeScope and ColumnDefinition.SharedSizeGroup. Well done and thanks!
jhon
Commented on 3.March 2011
good chaka...
unruledboy
Commented on 30.March 2011
truely awesome, I have been looking for this functionality for a long time, I will put it into test and come back to you
unruledboy
Commented on 30.March 2011
Hi, I tried you method, all the text content are not rendered(the TextBlock showing nothing, even I place a button and bind Name for the content, still nothing). I am sure there is data, and before using data template, it's showing.


&lt;DataTemplate x:Key=&quot;DefaultDataTemplate&quot;&gt;
&lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
&lt;tree:RowExpander /&gt;
&lt;CheckBox IsChecked=&quot;{Binding Selected}&quot; /&gt;
&lt;Image Height=&quot;16&quot; Margin=&quot;2, 0, 5, 0&quot; Source=&quot;{Binding Converter={StaticResource TaskImageConverter}}&quot; Width=&quot;16&quot; /&gt;
&lt;TextBlock Style=&quot;{StaticResource TaskItemStyle}&quot; Text=&quot;{Binding Name}&quot; /&gt;
&lt;/StackPanel&gt;
&lt;/DataTemplate&gt;
&lt;my:ResultCellTemplateSelector x:Key=&quot;templateSelector&quot;
DefaultDataTemplate=&quot;{StaticResource DefaultDataTemplate}&quot;/&gt;



&lt;Grid&gt;
&lt;tree:TreeList x:Name=&quot;tlResults&quot;&gt;
&lt;tree:TreeList.View&gt;
&lt;GridView&gt;
&lt;GridView.Columns&gt;
&lt;GridViewColumn Width=&quot;500&quot; Header=&quot;Name&quot; CellTemplateSelector=&quot;{StaticResource templateSelector}&quot;&gt;
&lt;/GridViewColumn&gt;
&lt;GridViewColumn Header=&quot;Size&quot; Width=&quot;90&quot; DisplayMemberBinding=&quot;{Binding Converter={StaticResource FileSizeConverter}}&quot; /&gt;
&lt;/GridView.Columns&gt;
&lt;/GridView&gt;
&lt;/tree:TreeList.View&gt;
&lt;/tree:TreeList&gt;
&lt;/Grid&gt;

unruledboy
Commented on 30.March 2011
sorry, it's my mistake, I used the template from another control. It's working fine now, thank you very much!
Wes
Commented on 15.April 2011
Hi,
This is the best PropertyGrid Tutorial I found. The best part is,
it also have code to select DataTemplate depend on DataType of each class property: bool use BooleanDataTemplate which is a checkbox; Enum use EnumDataTemplate which is a combobox.
I also like go a little further, add custom type: lookup, which will show as dropdown list, but the value list come from database. e.g.
property name: car manufacturere, value come from &quot;SELECT LOOKUP_VALUE FROM LOOKUP WHERE LOOKUP_KEY = 'CAR_MFG'&quot;, which will return a list like: Toyota, Ford, Nissan, Honda, VW, BMW, ...
If I have &gt; 1 lookup properties, how I can speciafy them? LookupDataTemplate1, LookupDataTemplate2, ..., then how to specify them in XAML Resources. and all DataTemplate are pre-defined in XAML, how I can do it in this case.
similar to EnumToListConverter, How I can create LookupmToListConverter1, LookupmToListConverter2?

Thank you,

Mikhail
Commented on 21.April 2011
I run example solution with VS 2010 and .NET 4. It starts but when scrolling I am getting following error:

'' is not a valid value for property 'ClickMode'.

Same for 'FlowDirection', 'HorizontalAlignment, ecc.
jones
Commented on 14.June 2011
@Mikhail: I get this Error while starting.
Try this with the Property DependencyPropertyInfo.Value in DependencyPropertyInfo.cs:
set { try { _element.SetValue (_descriptor.DependencyProperty, value); } catch { } }

I suppose the error occures, because the Comboboxes have no item selected...
Ajay
Commented on 15.June 2011
Really nice articles

Name
E-Mail (optional)
Comment