May 29, 2012 08:43 by
Scott
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; }
}
then I can define implicit templates for them by writing templates such as 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>
where I have not specified a Key for these resources but have, instead, specified a DataType and that’s enough for Silverlight to figure it out.
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>
with a DataContext providing a view model like this one;
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; }
}
then whenever I add a Person to the ListBox the runtime will find the right implicit template to display the Person and if I add a Vehicle to the ListBox then the runtime will do the right thing there too;
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>
and so then both the ListBox on the left and the ContentPresenter on the right are using implicit templates to display content;
(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>
and, naturally, you can also mix/match this implicit approach with the explicit approach that you’d use in Silverlight 4 today.
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.
May 22, 2012 11:02 by
Scott
May 14, 2012 08:40 by
Scott
This article will explore how to use the ViewBox control in Silverlight 5.
The ViewBox control allows you to place a child control such as Image within it in such a way that it will be scaled appropriately to fit the available without any distortion. It is typically used in 2D graphics.
We will begin with creating a new Silverlight 5 project.
Modify the existing XAML code of MainPage.xaml so that a Grid of 1 column and three rows is created. The code for the same is shown below:
<UserControl x:Class="SilverlightDemo.MainPage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006 mc:Ignorable="d" xmlns:sdk=http://schemas.microsoft.com/winfx/2006/xaml/presentation/ sdk HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid x:Name="LayoutRoot" Background="White" Height="300" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
</Grid>
</UserControl>
Drag and drop the Viewbox control from the Toolbox into the XAML code between the <Grid></Grid> tags. Specify its row and column in the grid to be 0. The resulting code is seen below.
<UserControl x:Class="SilverlightDemo.MainPage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006 mc:Ignorable="d" xmlns:sdk=http://schemas.microsoft.com/winfx/2006/xaml/presentation/ sdk HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:Viewbox Grid.Row="0" Grid.Column="0" Height="120" Width="120">
</controls:Viewbox>
</Grid>
</UserControl>
Right click on the project name in the Solution Explorer pane and select Add Existing Item option. Choose the image "Winter.jg" from the My Documents\My Pictures\Sample Pictures folder.
Drag and drop an Image control in between the <controls:ViewBox> and </controls:ViewBox> tag and modify its code as shown below, to specify its source and size.
<Grid x:Name="LayoutRoot" Background="White" Height="300" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:Viewbox Grid.Row="0" Grid.Column="0" Height="120" Width="120">
<Image Source="Winter.jpg" Height="40" Width="40"></Image>
</controls:Viewbox>
</Grid>
Drag and drop another ViewBox and then an Image control in between the second <controls:ViewBox> and </controls:ViewBox> tag.
Modify the XAML as shown below:
<Grid x:Name="LayoutRoot" Background="White" Height="300" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:Viewbox Grid.Row="0" Grid.Column="0" Height="120" Width="120">
<Image Source="Winter.jpg" Height="40" Width="40"></Image>
</controls:Viewbox>
<controls:Viewbox Grid.Row="1" Grid.Column="0" Height="70" Width="90">
<Image Source="Winter.jpg" Height="40" Width="40"></Image></controls:Viewbox>
</Grid>
Save the solution, build and execute it. When you see the output, you will observe that the two images show no distortion whatsoever though their height and width are not the same. This has happened because of the ViewBox.
Conclusion : Thus, you learnt how to add and use a ViewBox control in a Silverlight application