In this post we are going to discuss a new feature expected to be released in Silverlight 5. This feature is implicit
DataTemplates. Those who come from WPF background to Silverlight often find it difficult to design without implicit DataTemplates. Well, this limitation has been worked in Silverlight 5 and it is available in the beta release. Silverlight 5 beta tools can be downloaded from here:
http://www.microsoft.com/download/en/details.aspx?id=23887
Let's create a sample Silverlight application and name it
AppSilverlightImplicitDataTemplates.
Make sure that you have Silverlight 5 option selected in the following screen displayed right after the previous one.
You would need a reference of System.Windows.Controls.Data.Input assembly for Labels. If you directly drag and drop the Label Control from Toolbox on the designer surface, the assembly is automatically referenced.
Let's suppose we have the following view model. It has a collection of students. We want the user to select a particular student and allow that to be edited.
namespace AppSilverlightImplicitDataTemplates
{
using System.Collections.ObjectModel;
using System.Collections.Generic;
public class MainViewModel : ViewModelBase
{
ObservableCollection<StudentViewModel> _students;
public ObservableCollection<StudentViewModel> Students
{
get
{
if (_students == null)
{
_students = new ObservableCollection<StudentViewModel>();
_students.Add(new StudentViewModel() { StudentFirstName = "Muhammad", StudentLastName = "Siddiqi" });
_students.Add(new StudentViewModel() { StudentFirstName = "Jayson", StudentLastName = "Abante" });
_students.Add(new StudentViewModel() { StudentFirstName = "Meena", StudentLastName = "Gulla" });
}
return _students;
}
}
}
}
The view model is inheriting from
ViewModelBase class. It is basically for providing general functionality to all view models specially implementation of
INotifyPropertyChanged interface. As you might have guessed, like this view model, all others view models in the application would also be inheriting from this.
namespace AppSilverlightImplicitDataTemplates
{
using System.ComponentModel;
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
In
MainViewModel we have used
StudentViewModel collection. It basically has two properties
StudentFirstName and
StudentLastName. Its definition can be as follows:
namespace AppSilverlightImplicitDataTemplates
{
using System.ComponentModel;
public class StudentViewModel : ViewModelBase
{
#region Notifiable Properties
string _studentLastName;
public string StudentLastName
{
get { return _studentLastName; }
set
{
_studentLastName = value;
OnPropertyChanged("StudentLastName");
}
}
string _studentFirstName;
public string StudentFirstName
{
get { return _studentFirstName; }
set
{
_studentFirstName = value;
OnPropertyChanged("StudentFirstName");
}
}
#endregion
}
}
As you can see above, it also inherits from
ViewModelBase. The two properties support change notification by calling
OnPropertyChanged method. In turn this would raise
PropertyChanged event. As we have discussed already that we would be needing to use this view model in two different types of views. One is just for display for selection based control used to display the collection of students. We also need a different view to allow a student to be edited.
For displaying in collection based control:
<UserControl x:Class="AppSilverlightImplicitDataTemplates.StudentDisplayView"
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" >
<TextBlock>
<Run Text="{Binding StudentLastName}" FontWeight="Bold" />
<Run Text="," />
<Run Text="{Binding StudentFirstName}" />
</TextBlock>
</UserControl>
For editing StudentViewModel:
<UserControl x:Class="AppSilverlightImplicitDataTemplates.StudentEditView"
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" >
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="93" />
<ColumnDefinition Width="307" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<sdk:Label Height="23" HorizontalAlignment="Left"
Margin="12,12,0,0" VerticalAlignment="Top"
Content="First Name" Width="83" Grid.ColumnSpan="2" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="8,8,0,0"
VerticalAlignment="Top" Width="287" Text="{Binding StudentFirstName}" Grid.Column="1" />
<sdk:Label Content="Last Name" Height="23" HorizontalAlignment="Left"
Margin="12,7,0,0" VerticalAlignment="Top" Width="83" Grid.Row="1" Grid.ColumnSpan="2" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="8,3,0,0"
VerticalAlignment="Top" Width="287" Grid.Row="1"
Text="{Binding StudentLastName}" Grid.Column="1" />
</Grid>
</UserControl>
Using UserControls in DataTemplate
By default we need the StudentViewModel type of objects to be using the display one. So we can define it as application resource. Just updated
App.xaml as follows:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AppSilverlightImplicitDataTemplates.App"
xmlns:local="clr-namespace:AppSilverlightImplicitDataTemplates"
>
<Application.Resources>
<DataTemplate DataType="local:StudentViewModel">
<local:StudentDisplayView />
</DataTemplate>
</Application.Resources>
</Application>
Now we define the Main application view. As we have discussed, we need to provide a collection of Students and allow the user to select any one of them and edit that.
<UserControl x:Class="AppSilverlightImplicitDataTemplates.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"
xmlns:local="clr-namespace:AppSilverlightImplicitDataTemplates"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<UserControl.DataContext>
<local:MainViewModel />
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="97*" />
<ColumnDefinition Width="303*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="43*" />
<RowDefinition Height="257*" />
</Grid.RowDefinitions>
<sdk:Label Height="22" HorizontalAlignment="Left" Margin="11,18,0,0"
Name="label1" VerticalAlignment="Top" Width="86"
Content="Select Student" DataContext="{Binding Path=Students}" />
<ComboBox Height="24" HorizontalAlignment="Left" Margin="6,14,0,0"
Name="cmbStudents" VerticalAlignment="Top" Width="285"
ItemsSource="{Binding Students}" Grid.Column="1" />
<ContentControl
DataContext="{Binding ElementName=cmbStudents, Path=SelectedItem}"
Content="{Binding}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Margin="11,18,0,0"/>
</Grid>
</UserControl>
Now lets run the application. It appears as follows:
Now select a student from the combo box. The same student is loaded in the
ContentControl as follows:
Now we need the
ContentControl to be using the editing type of
UserControl for
StudentViewModel so that it could be edited. Let's override it as follows in the main view:
<UserControl x:Class="AppSilverlightImplicitDataTemplates.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"
xmlns:local="clr-namespace:AppSilverlightImplicitDataTemplates"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<UserControl.DataContext>
<local:MainViewModel />
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="97*" />
<ColumnDefinition Width="303*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="43*" />
<RowDefinition Height="257*" />
</Grid.RowDefinitions>
<sdk:Label Height="22" HorizontalAlignment="Left" Margin="11,18,0,0"
Name="label1" VerticalAlignment="Top" Width="86"
Content="Select Student" DataContext="{Binding Path=Students}" />
<ComboBox Height="24" HorizontalAlignment="Left" Margin="6,14,0,0"
Name="cmbStudents" VerticalAlignment="Top" Width="285"
ItemsSource="{Binding Students}" Grid.Column="1" />
<StackPanel Margin="11,18,0,0" Grid.Row="1"
Grid.Column="0" Grid.ColumnSpan="2" >
<StackPanel.Resources>
<DataTemplate DataType="local:StudentViewModel" >
<local:StudentEditView />
</DataTemplate>
</StackPanel.Resources>
<ContentControl
DataContext="{Binding ElementName=cmbStudents, Path=SelectedItem}"
Content="{Binding}"
/>
</StackPanel>
</Grid>
</UserControl>
Here we have thrown the
ContentControl inside a
StackPanel. In the Resources section of the
StackPanel, we have overridden the
DataTemplate for
StudentViewModel. Since local resource have preference over application level resources so this
DataTemplate is applied for the
StudentViewModel in
ContentControl. When we run the application and select a student, the instance is loaded in the
ContentControl with correct
DataTemplate applied.
Download: