Silverlight 5 Tidbits–Multi-Column Layouts XNA for Silverlight developers: Part 9 - Navigation and structure

Silverlight 5 Tidbits–Implicit Data Templates

Published on Wednesday, April 20, 2011 6:55:00 PM UTC in Programming

Edit 2011-12-10: This article is compatible with the final version of Silverlight 5 (5.0.61118.0).

This post is part of a mini series about Silverlight 5:

Silverlight 4 introduced the concept of implicit styles. That is, styles which are not referred to by key explicitly, but that are applied to a certain type of visual elements automatically. The next version of Silverlight introduces implicit data templates, a concept that works in a similar way for your data types. This feature once again is a step of Silverlight towards its bigger brother WPF where implicit data templates have been available already.

The problem

One scenario for implicit templating is when you want to use the same data template for a certain type throughout your application. At the moment you have to e.g. define this template in your application resources and reference it explicitly whenever you want to use it, which is tedious and requires a lot of repetitive code.

Another typical problem is that sometimes you want to treat different data types in a similar manner, for example when you use them together in e.g. a single list box or other container. This often is the case when those types share a common base class. One sample that is often used for this is a person base class in your application that has derived classes for let's say employees, managers and customers. When you have a collection of persons, you might want to use different visualizations for each item based on the actual type.

The same applies e.g. when you work with data aggregation from different sources. Let's say you want to create an application that shows all kinds of updates from different social media like Twitter, Facebook and RSS. If you want to put all these into a single list to show them to your users but have different views for each type, then implicit data templates is what you need.

The situation so far

As I said before, WPF had support for this for a while, but it was missing in Silverlight. People came up with different solutions to work around this limitation, like deriving from existing controls or using value converters. For example, if you derive from content control you are able to react to changes of the content and apply a template based on the type of the new content. Or you can use a value converter that returns a template based on the type of the bound object and use it to set properties like the content control's content template.

All these solutions have in common that you need quite some amount of code to make them work. Often they are not very generic and require the use of a certain structure or lookup tables. Jeremy Likness posted a particularly flexible solution based on MEF that stands out against most others regarding this.

What's new in Silverlight 5

In the next version of Silverlight you can define data templates without a key in your resources. Instead, you specify the data type it should be applied to, like this:

<Grid.Resources> <DataTemplate DataType="MyType"> ... </DataTemplate> </Grid.Resources> 

By doing so, Silverlight will use this template whenever "MyType" is used in the scope where the resource is available. Let's look at an example. Add a namespace declaration like this to a Silverlight page:

xmlns:System="clr-namespace:System;assembly=mscorlib" 

The following snippet defines a data template for the "String" type. The template uses two text blocks to show the actual string and append a "(length = n)" suffix to it, where n is bound to the Length property of the string. The rest of the code contains two list boxes, one in the scope of the implicit data template, the other one outside:

<StackPanel x:Name="LayoutRoot" Background="White"> <Grid> <Grid.Resources> <DataTemplate DataType="System:String"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding StringFormat='\{0\} (length = '}" /> <TextBlock Text="{Binding Length, StringFormat='\{0\})'}" /> </StackPanel> </DataTemplate> </Grid.Resources> <ListBox x:Name="MyListBox" /> </Grid> <Grid> <ListBox x:Name="MyOtherListBox" /> </Grid> </StackPanel> 

Let's now fill the list boxes with some sample strings in code behind:

MyData = new ObservableCollection<string>
                {
                    "Test", 
                    "Another test", 
                    "A third test",
                    "Test four" };

MyListBox.ItemsSource = MyData;
MyOtherListBox.ItemsSource = MyData;

The result you'll get out of this is something like:

image

As you can see, the first list box has picked up the defined data template automatically, even though we didn't specify any reference to it. The second list box however uses the default representation (a call to the "ToString" method) because the implicit data template is not within the scope of this list box. This is an example how you can define a common template for a specific type that is then used throughout your application (if put into the application resources) or throughout the scope where it is available.

Of course you could also override the implicit data template of the first list box by declaring a different local template or by referencing a different data template resource explicitly.

Another example

Let's use one of the samples we've talked about above. It uses a class hierarchy like this:

public class Person {
    public string Name { get; set; }
}

public class Manager : Person { }
public class Employee : Person { }

We are now able to define different templates for managers and normal employees that in our case use different foreground colors. Of course you could customize this completely.

<Grid> <Grid.Resources> <DataTemplate DataType="local:Manager"> <TextBlock Foreground="Red" Text="{Binding Name}" /> </DataTemplate> <DataTemplate DataType="local:Employee"> <TextBlock Foreground="Black" Text="{Binding Name}" /> </DataTemplate> </Grid.Resources> <ListBox x:Name="MyPersons" /> </Grid> 

If we use some sample data and fill the items source of the list box with it, the result will look like:

image

This adds a lot of flexibility to handling these scenarios without using custom solutions and work arounds.

Limitations

Even though it's nice to finally have implicit data templates in Silverlight, they are still not able to tackle all scenarios. WPF has additional features like the DataTemplateSelector class that offers even more flexibility. For example it allows you to select different templates for the same type based on property values of the current item. This comes in handy if your data items really all are of the same type but you want to use different templates based on certain values. A sample for that would be a task list, as shown in the documentation about data templating in WPF, where you want a high-priority task to appear visually completely different from normal tasks. If you need such functionality, you have to revert back to custom solutions for now.

Note on the beta version

At the moment, you might receive "Invalid XAML" error messages in Visual Studio when you use the new implicit data template feature. You can safely ignore those errors, the templates will work fine when you run your application. [This does not apply to the final release]

Tags: Silverlight · Silverlight 5