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
OgiBoho
Commented on 12.August 2009
This is truly awesome article. It helped me a lot and it gave me good ideas.
dawmail333
Commented on 2.November 2009
THANK YOU! I'd been searching to try and work out how to use IsSelected with a custom source for a while now. Thank you again!
chandrapal
Commented on 5.November 2009
This is a good article. I made same like this.using this article
Eric
Commented on 18.November 2009
Hi,
I'm really stuck here with my listbox datatemplate:

I have a listbox where its datatemplate is a custom control
The lsitbox is bind to a datatable.
The datatable contains a integer GenderID (integer)
The customcontrol contains several textboxes and a combobox (gender)
All controls in the customcontrols are xaml binded and wotk perfectly, except for the combobox.
The problem is that the IstemsSource for the combobox is loaded after the control is initialized in the codebehind, meaning that the selectedvalue binding in xaml doesn't work.
The ItemsSource of the combobox is a datatable with 2 fields (ID (integer) & Gender(string)).
My Code:
'Fill the datatable
Dim oTBL As DataTable = GetGenderTBL()
Dim oBind As New Binding

With oCOMBO
.DataContext = oTBL
.DisplayMemberPath = "Gender"
.SelectedValuePath = "ID"
.SetBinding(ItemsControl.ItemsSourceProperty, oBind)
End With


Combo xaml:
<ComboBox Name="LstGender" Grid.Row="0" Grid.Column="7"
SelectedValue="{Binding Path=GenderID}"></ComboBox>

When running, the combobox list contains the items from the gender table, but no item is selected, the binding with Listbox GenderID doesn't work.

How can I load the combo ItemsSource before the controls in the listbox item are binding ?

Rgds,

Eric
yjmyzz
Commented on 7.December 2009
awesome !
Shankar
Commented on 9.December 2009
Nice to read...... ThankQ.
Meenatchi
Commented on 10.December 2009
Seems a nice article.It would be Great,if more explanation is given,especially for the beginners.
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