How the Presentation Model could look like when using Silverlight 2.0
In this post I will give you an example how the Presentation Model pattern could be implemented when using Silverlight 2.0. I will not dig deep into the Presentation Model, so if you don’t hear of it or want to read more about it, you can visit this page.
A short description of the Presentation Model follows here:
Represent the state and behavior of the presentation independently of the GUI controls used in the interface
To make the code examples in this post short, I have only used one property in my original domain entity, and the entity used in the post is Name. It only has one property called Name, to make it easy to identify objects in the example, I have added some suffix, which I don’t use in my real applications. So the Name entity has the name NameEntity. The NameEntity from the domain model (or can be a DataContract) look likes this:
public class NameEntity { public string Name { get; set; } }
I decided to use the Repository pattern on the Client side, so the Repository responsible for the NameEntity has the name NameRepository. On the client-side the Repository can for example make a call to a WCF service on the server side. When I use the Repository Pattern, I make sure all my Repositories implements an interface, the reason to this is to follow the Dependency Inversion Principle, it will also make it easier for me to write unit test. Here is the code for the NameRepository:
public interface INameRepository { NameEntity GetName(); void SaveName(NameEntity name); } public class NameRepository : INameRepository { public NameEntity GetName() { //Make a WCF call all use ADO.Net Data Services etc. return new NameEntity() { Name = "John Doe" }; } public void SaveName(NameEntity name) { //Make a call to a WCF service or use ADO.Net Data Services etc. } }
Note: I haven’t implemented the call to a WCF Service, or the use of ADO.Net Data Services in this example.
When using the Presentation Model pattern, we will create a class which should represents a model for presentation purpose. The following code is the Presentation Model for the NameEntity:
public class NamePresentationModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private INameRepository _nameRepository; private NameEntity _nameEntity; public NamePresentationModel(INameRepository nameRepository) { if (nameRepository == null) throw new ArgumentNullException("nameRepository"); _nameRepository = nameRepository; } public string Name { get { CheckIfNameEntityIsLoaded(); return _nameEntity.Name; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("Name can't be set to null or an empty string!"); CheckIfNameEntityIsLoaded(); _nameEntity.Name = value; RaisePropertyChanged("Name"); } } public void Load() { _nameEntity = _nameRepository.GetName(); } public void Save() { _nameRepository.SaveName(_nameEntity); } private void CheckIfNameEntityIsLoaded() { if (_nameEntity == null) throw new ArgumentException("You must first call the Load method of the NamePresentationModel!"); } protected void RaisePropertyChanged(string propertyName) { var propertyChanged = this.PropertyChanged; if (propertyChanged != null) propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }
The decided to implement the INotifyPropertyChanged interface if we are going to bind the Presentation Model’s Name property to several UIElement. I decided to make sure I could pass the type INameRepository as an parameter to the Presentation Model’s constructor. I want the Presentation Model to handle the actions and also to make sure I don’t add to much code or dependency to the Code behind file. As you can see in the code, I NEVER pass my NameEntity to the User Interface, instead the Presentation Model is the new model to be use on a User Interface level (bind to UIElements etc). Here is the Code behind of the XAML page:
public partial class Page : UserControl { private NamePresentationModel _namePresentationModel; public Page() { InitializeComponent(); _namePresentationModel = new NamePresentationModel(new NameRepository()); this.Loaded += Page_Loaded; } void Page_Loaded(object sender, RoutedEventArgs e) { LoadFromPresentationModel(); } private void Button_Click(object sender, RoutedEventArgs e) { _namePresentationModel.Save(); } private void LoadFromPresentationModel() { _namePresentationModel.Load(); myTextBox.Text = _namePresentationModel.Name; } private void SyncWithPresentationModel() { _namePresentationModel.Name = myTextBox.Text; } }
As you can see the code in the code behind page is relative clean. In this code example I have manually populate the User Interface with information, but we can also use data binding (more about that later in this post).
In the Page constructor I instantiate the Presentation Model to be used for the current View, I also inject an instance of the NameRepository object to the NamePresentaitonModel’s constructor. I could have hidden the dependency of the NameRepository in the NamePresentationModel, but that will violate the Dependency Inversion Principle, and if I want to write a Unit test for my NamePresentationModel, I can now simply inject a fake object of the NameRepository. One good idea here could be the use of the Factory pattern to create the Presentation Model, by doing so we could make sure the Page don’t even need to know about the Repository passed to the Presentation Model. I could also make sure that the default constructor of the Presentation Model instantiate the Repository, by doing it I would have the possibility to inject a Repository, or remove the instantiation of the Repository within the code behind.
public NamePresentationModel() { _nameRepository = new NameRepository(); }
public Page() { InitializeComponent(); _namePresentationModel = new NamePresentationModel(new NameRepository()); this.Loaded += Page_Loaded; }
I made a call to the PresentationModel’s Load method within the Page_Loaded event handler. I don’t want the Code-behind to be responsible for the use of the Repositories, so I gave the Presentation Model the responsibility instead. The NamePresentationModel class, will more or less remind us of the Active Record pattern. If you look at the code behind, you can see that the Button_Click will make a call to the Presentation Model’s Save method. The reason why the Save method is added to the Presentation Model, is to simulate the Save button’s “event” when writing a Unit test for example.
The code behind will have the responsibility to map the Presentation Model to the User Interface. Here is the XAML used in this example:
<UserControl x:Class="ICommandExample.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:Name="LayoutRoot" Background="White"> <StackPanel VerticalAlignment="Center"> <TextBox Margin="10" x:Name="myTextBox"></TextBox> <Button Margin="10" Content="Save" Click="Button_Click"></Button> </StackPanel> </Grid> </UserControl>
Instead of letting the code behind map the Presentation Model to the UIElements, we can use the Binding expression and also take advantage of User Input validation (you can read about User Input Validation in Silverlight 2.0 in my previous post). Here is the XAML code where DataBinding is used and the code is followed by the new code behind code:
<UserControl x:Class="ICommandExample.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:Name="LayoutRoot" Background="White"> <StackPanel x:Name="myStackPanel" VerticalAlignment="Center"> <TextBox Margin="10" x:Name="myTextBox" Text="{Binding Name, Mode=TwoWay}"></TextBox> <Button Margin="10" Content="Save" Click="Button_Click"></Button> </StackPanel> </Grid> </UserControl>
public partial class Page : UserControl { private NamePresentationModel _namePresentationModel; public Page() { InitializeComponent(); _namePresentationModel = new NamePresentationModel(new NameRepository()); this.Loaded += Page_Loaded; } void Page_Loaded(object sender, RoutedEventArgs e) { LoadFromPresentationModel(); } private void Button_Click(object sender, RoutedEventArgs e) { _namePresentationModel.Save(); } private void LoadFromPresentationModel() { _namePresentationModel.Load(); myStackPanel.DataContext = _namePresentationModel; } }
Because the Mode of the Binding expression is set to TwoWay, we don’t need to get the value of the TextBox when we hit the save button, because it will be automatically set to the new value of the TextBox.