Note: these are early notes based on some initial experiments with the Silverlight 5 beta, apply a pinch of salt to what you read.
One of the powerful new features around templating in the Silverlight 5 beta is the ability to produce a DataTemplate that will be implicitly associated with a particular data type.
For example, if I have these 2 simple types Person and Vehicle;
- public class Person
- {
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public int Age { get; set; }
- }
- public class Vehicle
- {
- public string Type { get; set; }
- public int Wheels { get; set; }
- }
these;
- <UserControl.Resources>
- <DataTemplate
- DataType="local:Person">
- <StackPanel>
- <TextBlock
- Text="{Binding FirstName}" />
- <TextBlock
- Text="{Binding LastName}" />
- <TextBlock
- Text="{Binding Age}" />
- </StackPanel>
- </DataTemplate>
- <DataTemplate
- DataType="local:Vehicle">
- <StackPanel>
- <TextBlock
- Text="{Binding Type}" />
- <TextBlock
- Text="{Binding Wheels}" />
- </StackPanel>
- </DataTemplate>
- </UserControl.Resources>
If I have a scenario like this one where I have a ListBox bound to a set of Items;
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition />
- <RowDefinition
- Height="Auto" />
- <RowDefinition
- Height="Auto" />
- </Grid.RowDefinitions>
- <ListBox
- ItemsSource="{Binding Items}">
- </ListBox>
- <Button
- Command="{Binding AddPerson}"
- Content="Add Person"
- Grid.Row="1" />
- <Button
- Command="{Binding AddVehicle}"
- Content="Add Vehicle"
- Grid.Row="2" />
- </Grid>
- public class ViewModel
- {
- public ViewModel()
- {
- this.Items = new ObservableCollection<object>();
- this.AddPerson = new SimpleCommand(() =>
- {
- this.Items.Add(
- new Person()
- {
- FirstName = "TestFirst",
- LastName = "TestLast",
- Age = 22
- });
- });
- this.AddVehicle = new SimpleCommand(() =>
- {
- this.Items.Add(
- new Vehicle()
- {
- Type = "Car",
- Wheels = 4
- });
- });
- }
- public ObservableCollection<object> Items { get; set; }
- public ICommand AddPerson { get; set; }
- public ICommand AddVehicle { get; set; }
- }
and, if for example I was to make my ViewModel implement property change notification and then bind up a new property called SelectedItem to my ListBox then I can bring in a ContentPresenter and it will also make use of the implicit template as in;
- <UserControl.Resources>
- <DataTemplate
- DataType="local:Person">
- <StackPanel>
- <TextBlock
- Text="{Binding FirstName}" />
- <TextBlock
- Text="{Binding LastName}" />
- <TextBlock
- Text="{Binding Age}" />
- </StackPanel>
- </DataTemplate>
- <DataTemplate
- DataType="local:Vehicle">
- <StackPanel>
- <TextBlock
- Text="{Binding Type}" />
- <TextBlock
- Text="{Binding Wheels}" />
- </StackPanel>
- </DataTemplate>
- </UserControl.Resources>
- <UserControl.DataContext>
- <local:ViewModel />
- </UserControl.DataContext>
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition />
- <RowDefinition
- Height="Auto" />
- <RowDefinition
- Height="Auto" />
- </Grid.RowDefinitions>
- <ListBox
- ItemsSource="{Binding Items}"
- SelectedValue="{Binding SelectedItem,Mode=TwoWay}" />
- <Button
- Command="{Binding AddPerson}"
- Content="Add Person"
- Grid.Row="1" />
- <Button
- Command="{Binding AddVehicle}"
- Content="Add Vehicle"
- Grid.Row="2" />
- <ContentPresenter
- Grid.Column="1"
- Content="{Binding SelectedItem}" />
- </Grid>
(as an aside, I also tried this with a ContentPresenter inside a Tooltip and it didn’t work for me so far in the beta).
Naturally, you can override these implicit templates so if I want a different template for my ContentPresenter I can simply add an implicit template that is nearer to the ContentPresenter in the hierarchy of resource resolution as in;
- <UserControl.Resources>
- <DataTemplate
- DataType="local:Person">
- <StackPanel>
- <TextBlock
- Text="{Binding FirstName}" />
- <TextBlock
- Text="{Binding LastName}" />
- <TextBlock
- Text="{Binding Age}" />
- </StackPanel>
- </DataTemplate>
- <DataTemplate
- DataType="local:Vehicle">
- <StackPanel>
- <TextBlock
- Text="{Binding Type}" />
- <TextBlock
- Text="{Binding Wheels}" />
- </StackPanel>
- </DataTemplate>
- </UserControl.Resources>
- <UserControl.DataContext>
- <local:ViewModel />
- </UserControl.DataContext>
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition />
- <RowDefinition
- Height="Auto" />
- <RowDefinition
- Height="Auto" />
- </Grid.RowDefinitions>
- <ListBox
- ItemsSource="{Binding Items}"
- SelectedValue="{Binding SelectedItem,Mode=TwoWay}" />
- <Button
- Command="{Binding AddPerson}"
- Content="Add Person"
- Grid.Row="1" />
- <Button
- Command="{Binding AddVehicle}"
- Content="Add Vehicle"
- Grid.Row="2" />
- <Grid
- Grid.Column="1">
- <Grid.Resources>
- <DataTemplate
- DataType="local:Vehicle">
- <StackPanel
- Orientation="Horizontal">
- <TextBlock
- Text="{Binding Type}" />
- <TextBlock
- Text="{Binding Wheels}" />
- </StackPanel>
- </DataTemplate>
- </Grid.Resources>
- <ContentPresenter
- Grid.Column="1"
- Content="{Binding SelectedItem}"/>
- </Grid>
- </Grid>
I think this is a pretty powerful addition to the Silverlight 5 binding/templating abilities and it’ll be interesting to see what other folks and frameworks do with it.
As a final note, I’m not sure at the time of writing whether there’s anything in Visual Studio 2010 Sp1 or in the Blend Preview for Silverlight 5 that deals with implicit templates – I’ve not seen anything just yet.
No comments:
Post a Comment