WPF DataTemplates


Hello again All!

Today im going to talk a little on how to use a DataTemplate in WPF.  Many people new to WPF generally run across the need to use a ItemsControl, ListBox, or ListView for their repeating item data.  Usually the first thing they find is that they have to set the ItemTemplate property which uses a DataTemplate to provide how each item should be visually represented.  I find that this is generally the extent of knowledge that people new to WPF have on DataTemplate.  This blog is going to go a bit more in depth into what a DataTemplate is and to show other ways we can use them!

So first lets actually define what a DataTemplate is.  A DataTemplate is a visual template that is a representation of data!  Wow were really into some deep logic here :) .  A DataTemplate directly relates to the concept of Content when using any form of a ContentControl.  To see more information of the WPF ContentControl Content model please see Controls Content Model Overview. When you apply a DataTemplate you are applying the Template to the Content directly.  When we think about what we can do with a DataTemplate we find there are different ways in which we can specify what data we want to template.

First lets go over an ItemsControl example.

When we look at the ItemsControl we have a property called ItemTemplate.  This property receives a DataTemplate.  Lets say we have a list of Person objects and we want to display LastName, FirstName.  This is how we could represent that in code.

<ItemsControl ItemsSource="{StaticResource MyPersonsList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding LastName}"/>
                <TextBlock Text=", "/>
                <TextBlock Text="{Binding FirstName}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Notice that our DataTemplate contains a horizontal StackPanel and the TextBlocks are arranged in a way that will show something like Doe, John for that entry in the Person list.  We have also not specified any attributes in the DataTemplate.  The reason this works is because control inheriting from ItemsControl automatically knows to go ahead and force the association of the template with the Content of each item in the ItemsControl.  Each item that is generated hosts a Content property which the template is applied to as stated above in defining a DataTemplate.

Before we move on to more complex concepts I’ll show how we can also use this concept in just a standard ContentControl.

<ContentControl Content="{StaticResource MySinglePerson}">
    <ContentControl.ContentTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding LastName}"/>
                <TextBlock Text=", "/>
                <TextBlock Text="{Binding FirstName}"/>
            </StackPanel>
        </DataTemplate>
    </ContentControl.ContentTemplate>
</ContentControl>

As you can see here we have specified the ContentTemplate property to display content for this control in the same way that we did in the ItemsControl.  This again shows the relation to the Content model in WPF where we saying that we want whatever content is set to the control to be displayed in a certain way.

Now that we have seen how to use a DataTemplate we have noticed that we have used the same DataTemplate for two different controls.  Well we definatly do not want to duplicate this everywhere in the application that has the Person object formatted in the same way.  Luckilly for us we can put DataTemplates as keyed resources!

Lets say that we have many different screens that all need to make use of this same data format.  What we can do is go into our App.xaml and add this template with a key to its resource collection.  (Note*  When WPF looks for a resource the App.xaml is the second to last place it checks when finding the resource.  This ensures that all of our screens in this project will be able to find the DataTemplate correctly).  Our App.xaml may look something like this.

<Application x:Class="DataTemplateExample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
        <DataTemplate x:Key="PersonNameDataTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding LastName}"/>
                <TextBlock Text=", "/>
                <TextBlock Text="{Binding FirstName}"/>
            </StackPanel>
        </DataTemplate>
    </Application.Resources>
</Application>

What we have done is said that we want to expose a DataTemplate to the entire application called PersonNameDataTemplate to use as we wish.  Now if we modify our ItemsControl and ContentControl code to use this template it would now look like this.

<ItemsControl ItemsSource="{StaticResource MyPersonList}"
              ItemTemplate="{StaticResource PersonNameDataTemplate}"/>

<ContentControl Content="{StaticResource MySinglePerson}"
                ContentTemplate="{StaticResource PersonNameDataTemplate}"/>

Now we have managed to reuse a common template with only having to specify it once!  We can reference this template anywhere we know we are setting Person objects as content to all be displayed in the exact same way.

Now lets go a final step and see how we can automatically have a DataTemplate applied without even needing to reference the template itself!  Imagine that we automatically know that everywhere in the application where we are using a Person object as content that it should all be displayed this same way.  This is not a real-case scenario as there will probably not be any application where all Person objects only show the name in this format.  But their are many cases where we would want to say that one object type should always be represented in the same way.  And this is what im going to talk about  next.

So for humors sake we want all Person objects to be displayed as LastName, FirstName in the entire application.  The way we do this is by not specifying a key and instead specifying a specific data type.  We still want to put the DataTemplate in the App.xaml Resources collection so that the entire app can automatically find the template when applicable.  The code should now look something like this.

<Application x:Class="DataTemplateExample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:models="clr-namespace:DataTemplateExample.Models"
    StartupUri="Window1.xaml">
    <Application.Resources>
        <DataTemplate DataType="{x:Type models:Person}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding LastName}"/>
                <TextBlock Text=", "/>
                <TextBlock Text="{Binding FirstName}"/>
            </StackPanel>
        </DataTemplate>
    </Application.Resources>
</Application>

We have added a namespace delcaration pointing to where we are storing our models so that we can get to the person type.  As you can see i have removed the key and instead added DataType=”{x:Type models:Person}”.  What this does is says that anytime in the entire application where an object of type Person is set as content that this DataTemplate should be used.  This is known as a global un-keyed template.  Unkeyed DataTemplates that specify a DataType will always be used when that type is set to Content.

Now that we have our global un-keyed DataTemplate this is how our ItemsControl and ContentControl would now look.

<ItemsControl ItemsSource="{StaticResource MyPersonList}"/>

<ContentControl Content="{StaticResource MySinglePerson}"/>

We have not specified any templates to be used, but the global template we have defined will automatically be used!  This is a very powerful technique that can be used accross many different aspects of WPF development. 

Lets say we wanted Themeing and in another Theme we wanted to always show FirstName, LastName.  Well we could create a second un-keyed DataTemplate and at runtime inject the new one into the Resource Tree lookup before our default and our UI will automatically change to reflect the new template!  Imagine this on a grand scale of being able to build complete lookless, themeable applications!  For more information on how the Resource lookups and Trees work please see Trees in WPF.

Global DataTemplates can also be a key player in the popular MVVM patthern for WPF.  You can create a DataTemplate representing a ViewModel so that all you have to do is create ViewModel’s and set them as content.  To see more about MVVM in WPF please see Josh Smith’s MSDN article WPF Apps With The Model-View-ViewModel Design Pattern.  Read the entire article and all code samples and you will find the DataTemplate relevance to this pattern.

Well i hope you all have enjoyed this article and learned something from it and hope you have a happy coding day!

  1. #1 by mpp on July 30, 2010 - 1:55 am

    <ItemsControl ItemsSource="{StaticResource MyPersonList}"

    and where and how MyPersonList should be defined???

  2. #2 by Pramod on November 29, 2010 - 2:06 pm

    Can I ‘Bind’ the ContentTemplate of a Content Control? Eg, Assume I have a class with two properties ‘string Name’ and ‘DataTemplate Template’. I want the content control to show ‘Name’ but use the template defined by ‘Template’ property. Is this possible? How?

    thanks and regards
    =Pramod

  3. #3 by Jason Rainwater on November 29, 2010 - 3:40 pm

    You could do this. Here is a quick example.

    ContentControl Content=”{Binding YourObject.Name}” ContentTemplate=”{Binding YourObject.Template}” />

    This assumes that the datacontext of your ContentControl is something that has a property called YourObject which is filled in with the two property class you are talking about.

    Is this what you are looking for?

Comments are closed.