Follow @PDSAInc Change Templates Dynamically in WPF - Paul Sheriff's Blog for the Real World

Paul Sheriff's Blog for the Real World

This blog is to share my tips and tricks garnered over 25+ years in the IT industry

Paul's Favorites

Change Templates Dynamically in WPF

WPF has the flexibility to modify the look of your controls dynamically at runtime with just a few lines of code. Take a look at Figures 1 and 2 and you will see two different views of the same list box and data. To accomplish this, you simply need to setup two different resources of XAML code that you can switch between at runtime.

More Detail 
Figure 1: More detail

Less Detail
Figure 2: Less detail

The Basic Form and the Data

This XAML form uses an XML file to fill in the ListBox control with the product data. There is a folder called \Images where the pictures for the various products are located. Below is a fragment of the XML file that contains the product data.

<Products>
  <Product>
    <ProductId>1</ProductId>
    <ProductName>PDSA .NET Productivity Framework</ProductName>
    <Price>5000</Price>
    <Logo>/Images/Framework.gif</Logo>
  </Product>
  ...
  ...
</Products>

An XmlDataProvider control is used to load this file and supply the data for the list box. The XAML code shown below is the setup of this XmlDataProvider. This XmlDataProvider is located within the Window.Resources section of this WPF Window.

<XmlDataProvider x:Key="xProducts"
                 Source="/Product.xml"
                 XPath="Products/Product" />

As you can see in the above code the Product.xml file is located in the root of the project. You use the XPath attribute to read to the node level where the actual data is within the XML file. Then you will be able to specify the element name of where the data is for displaying in the list box.

Create the XAML Templates

The next items in the Window.Resources section of this WPF Window are the <DataTemplates>. There are two data templates created as resources in this window. One has a key of “tmplMore” and one has a key of “tmplLess”. Below is the XAML code that is used to create the list box that looks like Figure 1. You can see the use of a Horizontal StackPanel control, and an Image control as the first control within that StackPanel.

<DataTemplate x:Key="tmplMore">
  <StackPanel Orientation="Horizontal">
    <Image Margin="8"
           Source="{Binding XPath=Logo}"
           Width="100"></Image>
    <Label Width="250"
           Content="{Binding XPath=ProductName}"></Label>
    <Label Width="100"
           Content="{Binding XPath=Price}"></Label>
  </StackPanel>
</DataTemplate>

Notice the data binding of the Source property of the image and the Content properties of the two labels. The Binding uses XPath attribute to signify the name of the element within the XML file. Remember that the XmlDataProvider has the first part of the XPath query, while each Binding is the element where the data is located that will be displayed in the list box.

The next data template created within the Window.Resources section has the key of “tmplLess” and looks like the XAML below. You can see that the Image control is missing from this template.

<DataTemplate x:Key="tmplLess">
  <StackPanel Orientation="Horizontal">
    <Label Width="250"
           Content="{Binding XPath=ProductName}"></Label>
    <Label Width="100"
           Content="{Binding XPath=Price}"></Label>
  </StackPanel>
</DataTemplate>

In the WPF Window is the definition of the list box control shown in the XAML listing below. Notice that the ItemsSource attribute is set to bind to the xProducts XmlDataProvider control. Also notice that the ItemTemplate is bound to the “tmplMore” data template resource. This is the default data template that is used when the window is first displayed.

<ListBox Margin="10,10,0,0"
         Height="300"
         Name="lstData"
         ItemsSource="{Binding Source={StaticResource xProducts}}"
         IsSynchronizedWithCurrentItem="True"
         ItemTemplate="{StaticResource tmplMore}">
</ListBox>

Switch Between the XAML Templates

You will write code in each button’s click event procedures, shown below, to switch between the two XAML templates. In each event procedure you create a variable to refer to a DataTemplate object. You then use the FindResource method of the current window to find the resource named either “tmplMore” or “tmplLess”. Once you have the data template object you can assign that to the ItemTemplate property of the list box control.

One thing to note is that you should include error handling within this code because if the FindResource method does not find the resource, then it will throw an exception. I purposely left out the code for brevity in this example.

Visual Basic

Private Sub btnMore_Click(ByVal sender As System.Object, _
 ByVal e As System.Windows.RoutedEventArgs) Handles btnMore.Click
  Dim tmpl As DataTemplate

  tmpl = DirectCast(Me.FindResource("tmplMore"), DataTemplate)
  lstData.ItemTemplate = tmpl
End Sub

Private Sub btnLess_Click(ByVal sender As System.Object, _
 ByVal e As System.Windows.RoutedEventArgs) Handles btnLess.Click
  Dim tmpl As DataTemplate

  tmpl = DirectCast(Me.FindResource("tmplLess"), DataTemplate)
  lstData.ItemTemplate = tmpl
End Sub


C#

private void btnMore_Click(object sender, RoutedEventArgs e)
{
  DataTemplate tmpl;

  tmpl = (DataTemplate)this.FindResource("tmplMore");
  lstData.ItemTemplate = tmpl;
}

private void btnLess_Click(object sender, RoutedEventArgs e)
{
  DataTemplate tmpl;

  tmpl = (DataTemplate)this.FindResource("tmplLess");
  lstData.ItemTemplate = tmpl;
}

Summary

In this article you learned to change templates on a list box control dynamically at runtime using the FindResource method. You simply need to create a couple of XAML templates that you will use to switch between the different views. You create these XAML templates in the Window.Resources section of the window. You give each template a unique name, and then write a little code to find each of the resources at runtime. Once you have located the appropriate resource, you assign it to the ItemTemplate property of the list box and WPF will change the look of the control instantly.


NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF Change Templates" from the drop-down.

Good Luck With Your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".

Posted: Nov 16 2009, 12:43 PM by psheriff | with 5 comment(s)
Filed under: ,

Comments

Al Loup said:

Nice how you switched templates. Is there any way, after the switch, to find out which template is in use by "lstData"?

Put another way, after you set 'lstData.ItemTemplate = tmpl' at runtime, is there a property you can check or a method you can use to check which template is currently in use, tmplLess or tmplMore? For example, a way to check the x:Key of the template-in-use?

thanks,  Al

al@alloup.com

# January 7, 2011 7:34 AM

psheriff said:

Al,

Not that I know of, however you could just keep a variable around that keeps track of it. In the Click events, just set the variable.

Paul

# January 7, 2011 12:20 PM

Mihai said:

Hi,

Do you know any way to do this in MVVM?

I have a dependency property that tells me what template i should use (an enum), but i cannot use ContentTemplateSelector, because the property does not belong to the object that is bound to the control.

Thanks,

Mihai

# April 19, 2011 8:30 AM

psheriff said:

Hello Mihai,

Check out this article: msdn.microsoft.com/.../ms742521.aspx. I believe it is doing somewhat you are trying to do toward the bottom of that article. If I get some time, I may try to post this as a blog.

Thanks,

Paul

# April 19, 2011 12:28 PM

Dheeraj said:

Thanks. It was very helpful article for me.

# October 18, 2012 10:23 AM