Implementing Windows Phone 7 DataTemplateSelector and CustomDataTemplateSelector
published on: 2/11/2011 | Views: N/A | Tags: Silverlight
by WindowsPhoneGeek
In this article I am going to explain how to create a DataTemplateSelector abstract class and custom DataTemplateSelector in Silverlight for Windows Phone 7. Basically a DataTemplateSelector will provide a way to choose a DataTemplate based on the data object and the data-bound element. Typically, you need some kind of DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object.
In short: DataTemplateSelector enables you to write some logic that chooses what DataTemplate to use for a particular item. You could even create an entirely new data template if needed to.
NOTE: DataTemplateSelector is a well known class in WPF but it is still not available for Silverlight.
Here is a popular question that I found while browsing through the dev forums:
"I have a list of different types of elements. I would like to display a different data template for different list elements, based on what type it is. "
The answer to this question is to use a kind of DataTemplateSelector. So in this article I will first explain how to implement a DataTemplateSelector abstract class and after that I will demonstrate how to implement your own CustomDataTemplateSelector . The final result is shown on the right image.
Implementing DataTemplateSelector abstract class
There are lots of different ways in which you can create a dynamic DataTemplateSelector. You can grab a piece of code from the default WPF implementation or try a different approach with ContentPtesenter of ValueConverter etc. In this article I will demonstrate how to create a DataTemplateSelector which derives from ContentControl (I will use ContentControl as a base class).
The first thing I need to mention is that I will create an abstract class with a virtual method SelectTemplate which provides logic to return the appropriate template based on the value of the Priority property (when overridden in any particular class that derives from DataTemplateSelector). I will also override the OnContentChanhed which comes from the base class. The source code is as follows:
public abstract class DataTemplateSelector : ContentControl
{
public virtual DataTemplate SelectTemplate(object item, DependencyObject container)
{
return null;
}
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
ContentTemplate = SelectTemplate(newContent, this);
}
}
How to create a CustomDataTemplateSelector
To create a custom data template selector first create a class that inherits from DataTemplateSelector and after that override the SelectTemplate method. Once your class is defined you can assign an instance of the class to the template selector property of your element.
I will create a FoodTemplateSelector class that will contain three different DataTemplates: Healthy, UnHealthy and NotDetermined. In the SelectTemplate method I will add some conditions that will select the appropriate DataTemplate based on a data context property value. Basically we will choose the right template based on the Type property value of our data source.
The FoodTemplateSelector class source code is as follows:
public class FoodTemplateSelector : DataTemplateSelector
{
public DataTemplate Healthy
{
get;
set;
}
public DataTemplate UnHealthy
{
get;
set;
}
public DataTemplate NotDetermined
{
get;
set;
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Data foodItem = item as Data;
if (foodItem != null)
{
if (foodItem.Type == "Healthy")
{
return Healthy;
}
else if (foodItem.Type == "NotDetermined")
{
return NotDetermined;
}
else
{
return UnHealthy;
}
}
return base.SelectTemplate(item, container);
}
}
And here is how our data class should looks like:
public class Data
{
public string Name
{
get;
set;
}
public string Description
{
get;
set;
}
public string IconUri
{
get;
set;
}
public string Type
{
get;
set;
}
}
I will use a data bound ListBox in order to demonstrate the usage of the FoodTemplateSelector. Here is the source code:
public MainPage()
{
InitializeComponent();
List<Data> list = new List<Data>();
Data item0 = new Data() { Name = "Tomato", IconUri = "Images/Tomato.png", Type = "Healthy" };
Data item1 = new Data() { Name = "Beer", IconUri = "Images/Beer.png", Type = "NotDetermined" };
Data item2 = new Data() { Name = "Fries", IconUri = "Images/fries.png", Type = "Unhealthy" };
Data item3 = new Data() { Name = "Sandwich", IconUri = "Images/Hamburger.png", Type = "Unhealthy" };
Data item4 = new Data() { Name = "Ice-cream", IconUri = "Images/icecream.png", Type = "Healthy" };
Data item5 = new Data() { Name = "Pizza", IconUri = "Images/Pizza.png", Type = "Unhealthy" };
Data item6 = new Data() { Name = "Pepper", IconUri = "Images/Pepper.png", Type = "Healthy" };
list.Add(item0);
list.Add(item1);
list.Add(item2);
list.Add(item3);
list.Add(item4);
list.Add(item5);
list.Add(item6);
this.listBox.ItemsSource = list;
}
Next I will create three different DataTemplates and will set them as an ItemTemplate of the ListBox. Note that each template is independent and not connected with the rest ones. This means that you are free to add whatever element you want in each of the templates. So you have one data source in three different Views.
The final result can be seen in the image on the left. And here is how each of the templates looks like:
Here is how the source code should looks like:
<ListBox x:Name="listBox" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<local:FoodTemplateSelector Content="{Binding}">
<local:FoodTemplateSelector.Healthy>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="YellowGreen" Width="400" Margin="10">
<Image Source="{Binding IconUri}" Stretch="None"/>
<TextBlock Text="{Binding Name}" FontSize="40" Foreground="Black" Width="280"/>
<TextBlock Text="healty" />
</StackPanel>
</DataTemplate>
</local:FoodTemplateSelector.Healthy>
<local:FoodTemplateSelector.UnHealthy>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="2" Width="400" Margin="10">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding IconUri}" Stretch="None"/>
<TextBlock Text="{Binding Name}" FontSize="40" Width="280"/>
<Image Source="Images/attention.png" Stretch="None" Margin="10,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</local:FoodTemplateSelector.UnHealthy>
<local:FoodTemplateSelector.NotDetermined>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="Gray" Width="400" Margin="10">
<Image Source="{Binding IconUri}" Stretch="None"/>
<TextBlock Text="{Binding Name}" FontSize="40" Width="280"/>
<Image Source="Images/question.png" Stretch="None" Margin="10,0,0,0"/>
</StackPanel>
</DataTemplate>
</local:FoodTemplateSelector.NotDetermined>
</local:FoodTemplateSelector>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
An the final result : each item uses different template depending on the Type property value:
Here are some helpful links with another approach of DataTemplateSelector implementation:
- Using a ValueConverter as a DataTemplateSelector in Silverlight
- DataTemplate Selector with Silverlight
That was all about how to implement a DataTemplateSelector abstract class and how to use it in Silverlight for Windows Phone 7. You can find the full source here:
I hope that the article was helpful.
You can also follow us on Twitter @winphonegeek
Comments
.
posted by: TH on 2/11/2011 7:50:19 PM
Thank you for writing this article.
How many templates can I use?
posted by: Thimoty on 2/11/2011 7:51:40 PM
Thanks for another great post. I am new to WP7 so my question is how many templates can I use?
cool stuff
posted by: Kinsoa on 2/11/2011 7:52:42 PM
Just found this post. Pretty cool stuff!
Incorrect example
posted by: Jake on 4/1/2011 3:42:08 PM
You have a CountryTemplateSelector in your xaml code. It should be FoodTemplateSelector
RE:Incorrect example
posted by: winphonegeek on 4/26/2011 10:41:34 PM
Thank you for pointing that out. Fortunately this was only a problem with the code spinet tool.The typo is now fixed.
Getting it to work with Sample Data
posted by: Eric on 5/10/2011 5:46:40 PM
Nice example! Thanks!
I had to do a little extra coding to get this to work with sample data in the designer, because the designer creates fake types. Here's what my template selector looks like (Notice that I use reflection to get the data I need for template selection):
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
ItemViewModel model = item as ItemViewModel;
ItemType itemType;
// Sample data in the designer uses a faked ItemViewModel
if(model == null)
{
Type modelType = item.GetType();
PropertyInfo info = modelType.GetProperty("ItemType");
itemType = (ItemType)info.GetValue(item, null);
}
else
{
itemType = model.ItemType;
}
switch(itemType)
{
case ItemType.SetSeparator:
return SetSeparator;
case ItemType.ColorIndicator:
return ColorIndicator;
default:
return SetSeparator;
}
return base.SelectTemplate(model, container);
}
posted by: Dave Fancher on 7/3/2011 7:18:08 AM
Thanks for this! I needed to select a template based on the actual type of object in a collection. This was the best solution I came across for WP7 and was easily adapted to my situation.
Design Mode Sample Data
posted by: dutzend on 8/1/2011 6:25:10 PM
Hi,
your post are very helpful!
How can i use Sample data in Design Mode, Erics Example works not for me i cant find the "ItemType".
Any Help?
thx dutzend
Templating on events
posted by: Cesar on 8/3/2011 6:05:58 PM
Is it possible to change the template of all ListBoxItems based on a click in the page that contains your ListBox?
Mango problem
posted by: Ido on 8/26/2011 9:01:11 AM
Hi, I used this example in the NODO release and it worked great. Once I upgraded my code to MANGO it stoped working. I get "Unspecified error". I tested your code and it is working on MANGO.
Any ideas?
Problem with local in xaml
posted by: yash on 10/21/2011 2:47:38 PM
I have problem with the xaml code .
Error 2 The type 'local:FieldTemplateSelector' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.
I am new to this windows development .
please help me .
Best Regards, Yash
posted by: Denis on 10/29/2011 10:45:00 PM
Thank you - very helpful!
Horizontal orientation
posted by: sunco on 11/26/2011 8:03:07 PM
Thanks for this great article.
Lets see i have this:
Data item0 = new Data() { Name = "Tomato", Type = "Healthy" };
Data item1 = new Data() { Name = "Ice-cream", Type = "Healthy" };
Data item2 = new Data() { Name = "Pepper", Type = "Healthy" };
Data item3 = new Data() { Name = "Beer", Type = "Healthy" };
Data item4 = new Data() { Name = "Fries", Type = "Unhealthy" };
Data item5 = new Data() { Name = "Sandwich", Type = "Unhealthy" };
Data item6 = new Data() { Name = "Pizza", Type = "Unhealthy" };
As you can see, the first 4 items are Healthy. I want to show 2 items in 1 row. Then, show the Unhealthy one by row
How can i do that ? I was playing with StackPanels and Orientation with no luck
RE: Horizontal orientation
posted by: winphonegeek on 11/29/2011 2:02:51 PM
You can use the WrapPanel if you want an overflow layout (horizontal or vertical). You can change the layout panel that is used by the list box control to order items as described in this article: http://www.windowsphonegeek.com/tips/working-with-itemspanel-in-wp7
RE: problem with local in xaml
posted by: winphonegeek on 11/29/2011 2:50:57 PM
You are probably missing a namespace declaration for your FieldTemplateSelector. You will need to add (at the beginning of the xaml file) something like below:
xmlns:local="clr-namespace:your-namespace-here"
Where instead of "your-namespace-here" you have to use the namespace where your FieldTemplateSelector class is.
Cool
posted by: Relevant on 12/30/2011 12:36:24 AM
Awesome, it works, thank you!
Very Useful
posted by: Vinod on 1/30/2012 4:03:18 PM
This sample has been very useful to support different listbox views - with checkbox and without checkbox). To support multiple selection for delete mode view.
posted by: F2006 on 2/14/2012 4:25:24 PM
Works great, thank you!
Our Top Articles & Free books
- Our FREE e-book: "Windows Phone Toolkit In Depth" 2nd edition
- 400+ Windows Phone Development articles in our Article Index
- 21 WP7 Toolkit in Depth articles covering all controls
- 12 WP7 Coding4Fun Toolkit in Depth articles covering all controls
- Performance Tips when creating WP7 apps
- Creating a WP7 Custom Control in 7 Steps
- WP7 working with VisualStates: How to make a ToggleSwitch from CheckBox
- What makes a WP7 App successful
- Creating theme friendly UI in WP7 using OpacityMask
- Implementing Windows Phone 7 DataTemplateSelector and CustomDataTemplateSelector
- All about Splash Screens in WP7 – Creating animated Splash Screen
- Getting Started with Unit Testing in Silverlight for WP7
- WP7 WatermarkedTextBox custom control
Our Top Tips & Samples
- All about WP7 Isolated Storage series
- WP7 Dynamically Generating DataTemplate in code
- 5 tips for a successful WP7 Marketplace submission
- WP7: Navigating to a page in different assembly
- WP7 ContextMenu: answers to popular questions
- WP7 ListBox: answers to popular questions
- WP7 working with Images: Content vs Resource build action
- WP7 Element Binding samples
- WP7 working with XML: reading, filtering and databinding
- Drawing in WP7: #2 Drawing shapes with finger
- WP7 TextBox Light theme problems - the solution
- Changing the WP7 Panorama Background Image dynamically with Animation
