1. MVVM provide application to code reuse.
2. Simplifies the application.
3. Easy to maintenance and provide maximum support for the testing.
What is MVVM?
Model-View-ViewModel (MVVM) is a design pattern which can be use in WPF and Silverlight.
Model : Entities (Most of the time directly connect with the application backend.)
View : Your silverlight screens.
ViewModel : The glue between the Model and View.
In Silverlight View and ViewModel will located in the client side and Model will located in server side.So We have to use Communication method to communicate between the Client and server side. Most of the time we user WCF Service for this.
Now we will implement a simple silverlight application using MVVM pattern.This example I will explain the Command and Property Binding using MVVM.
Business Requirement : We want to find the person information using person ID and we want to display person information in web form..Here Person information is stored in the server side.
Solution :
1. Create a new Silverlight application and name it as MVVMSample.Now Visual Studio will create Silverlight project and Web Application project for you.
2. Now right click on the MVVMSample.Web project and add New Class named by PersonData and implement the class as bellow.
namespace Index.Web { public class PersonData { public int PersonID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public string Address { get; set; } } }
3.Again Right Click on the MVVMSample.Web project and add New Class named by PersonRepository and implement the class as bellow.
using System.Collections.Generic; namespace Index.Web { public class PersonRepository { public IList<PersonData> Person{get;set;} public PersonRepository() { GeneratePersonList(); } private void GeneratePersonList() { Person = new List<PersonData>() { new PersonData() { PersonID = 1, FirstName = "Erandika", LastName = "Sandaruwan", Age=25, Address = "Delgoda" }, new PersonData() { PersonID = 2, FirstName = "Niluka", LastName = "Dilani", Age = 30, Address = "Kandy" }, new PersonData() { PersonID = 3, FirstName = "Chathura", LastName = "Achini", Age = 27, Address = "Colombo" }, new PersonData() { PersonID = 4, FirstName = "Florina", LastName = "Breban", Age = 25, Address = "Romania" }, }; } } }
4.Finally we want to add our silverlight enable WCF service to MVVMSample.Web project.To do that right click on the MVVMSample.Web project Select the Add New Item and then in Installed Template under Visual C# select the Silverlight.Now select the Silverlight-enable WCF Service and name it as PersonDataService.svc and click on the Add button.
Now implement the service class as bellow.
using System; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Activation; namespace Index.Web { [ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class PersonDataService { [OperationContract] public PersonData FindPerson(int personID) { return new PersonRepository().Person.Where(x => x.PersonID == personID).SingleOrDefault(); } } }
So here now we have completed our model part.So next we have to implement our View and ViewModel part.
5.First We will add our PersonDataService to our silverlight project.To do that In MVVMSample project right click on References and click on Add Service Reference and then Add References Window will open for you and click on Discover button and VS will display all the services that have been added to current solution. But here we have only one service.Give the Namesapce as PersonDataService and click OK button.(Remember before this you have to build your web application project first) and then service reference will added to the your silverlight project.
6. Now add new folder to Silverlight project and named it as ViewModel and add two classes named by MainPageViewModel. and ViewModelBase. Again add new folder called ServiceAgent and add a Interface called IPersonService.and implement the interface as bellow.
using System; using MVVMSample.PersonDataService; namespace MVVMSample.ServiceAgent { public interface IPersonService { void FindPerson(int personID,EventHandler<FindPersonCompletedEventArgs> callBack); } }
Now we want to implement PersonService class using IPersonService interface.So to do that add a new class to ServiceAgent folder and named it as PersonService and then implement the class as bellow.
using System; using MVVMSample.PersonDataService; namespace MVVMSample.ServiceAgent { public class PersonService:IPersonService { private PersonDataServiceClient client = new PersonDataServiceClient(); public void FindPerson(int personID, EventHandler<FindPersonCompletedEventArgs> callBack) { client.FindPersonCompleted += callBack; client.FindPersonAsync(personID); } } }
7. Now we have to implement our ViewModel.Note that here we want to use ICommand interface for the implement the command which it bind to Search button. Here we will use Prism Framework.So we do not want to implement the Command and we can directly use DelegateCommand.You can download the Prism framework from following URL http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=4922
And you have to add as Microsoft.Practice.Prism.dll which is belongs to silverlight as reference to your silverlight project.Now we will start implement our MainPageViewModel and ViewModelBase classes.So First we will implement our ViewModelBase class as bellow.
using System.ComponentModel; namespace MVVMSample.ViewModel { public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public bool IsDesignTime { get { return DesignerProperties.IsInDesignTool; } } protected virtual void OnPropertyChanged(string propertyName) { var propertyChanged = PropertyChanged; if (propertyChanged != null) { propertyChanged(this,new PropertyChangedEventArgs(propertyName)); } } } }
Here you can see that our ViewModelBase class in implemented from INotifyPropertyChanged interface.This is very important in silverlight data binding to notify controls and other objects when a bound property value changes.So by using our ViewModelBase class we can reuse it across the multiple ViewModel. So Now we will implement our MainPageViewModel as bellow.
using System.Windows.Input; using MVVMSample.PersonDataService; using MVVMSample.ServiceAgent; using Microsoft.Practices.Prism.Commands; namespace MVVMSample.ViewModel { public class MainPageViewModel : ViewModelBase { private PersonService _personService; public MainPageViewModel() { if (IsDesignTime != true) { this._personService = new PersonService() ; this.FindPersonCommand = new DelegateCommand<object>(this.FindPersonByID); } } private PersonData _personData; public PersonData PersonData { get { return _personData; } set { if (_personData != value) { _personData = value; OnPropertyChanged("PersonData"); } } } private int _personID; public int PersonID { get { return _personID; } set { if (_personID != value) { _personID = value; OnPropertyChanged("PersonID"); } } } public ICommand FindPersonCommand{get;set;} private void FindPersonByID(object obj) { if (PersonID != 0) { _personService.FindPerson(PersonID, (s, e) => PersonData = e.Result); } } } }
You can see that we we inherit our MainPageViewModel class from ViewModelBase class and we reuse IsDesignTime property and OnPropertyChanged method in here. Also note that we are using DelegateCommand here.Which is come from Microsoft.Practice.Prism.dll and so we do not want to worry to implement this event.So now our MainPageViewModel is ready now and we have to bind data to our silverlight View.In this example we are going to bind PersonData and PersonID property and FindPersonCommand command to silverlight View.
8. Now we will create our silverlight View and Bind the Data from our ViewModel.You implement our view as bellow.
<UserControl x:Class="MVVMSample.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:viewModel="clr-namespace:MVVMSample.ViewModel" d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"> <UserControl.DataContext> <viewModel:MainPageViewModel/> </UserControl.DataContext> <Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="25"/> <RowDefinition Height="25"/> <RowDefinition Height="5"/> <RowDefinition Height="25"/> <RowDefinition Height="5"/> <RowDefinition Height="25"/> <RowDefinition Height="5"/> <RowDefinition Height="25"/> <RowDefinition Height="5"/> <RowDefinition Height="25"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <sdk:Label Height="25" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" Name="label1" VerticalAlignment="Center" Width="120" Content="Person ID :" /> <TextBox Height="25" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Name="txtPersonID" VerticalAlignment="Top" Width="150" Text="{Binding PersonID, Mode=TwoWay}" /> <Button Grid.Row="1" Grid.Column="2" Content="Search" Height="25" HorizontalAlignment="Left" Name="btnSearch" VerticalAlignment="Top" Width="75" Command="{Binding FindPersonCommand}" /> <sdk:Label Height="25" Grid.Row="3" Grid.Column="0" HorizontalAlignment="Right" Name="label2" VerticalAlignment="Center" Width="120" Content="First Name :" /> <TextBox Height="25" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left" Name="txtFirstName" VerticalAlignment="Top" Width="200" Text="{Binding Path=PersonData.FirstName, Mode=TwoWay}" /> <sdk:Label Height="25" Grid.Row="5" Grid.Column="0" HorizontalAlignment="Right" Name="label3" VerticalAlignment="Center" Width="120" Content="Last Name :" /> <TextBox Height="25" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left" Name="txtLastName" VerticalAlignment="Top" Width="200" Text="{Binding Path=PersonData.LastName, Mode=TwoWay}" /> <sdk:Label Height="25" Grid.Row="7" Grid.Column="0" HorizontalAlignment="Right" Name="label4" VerticalAlignment="Center" Width="120" Content="Age :" /> <TextBox Height="25" Grid.Row="7" Grid.Column="1" HorizontalAlignment="Left" Name="txtAge" VerticalAlignment="Top" Width="200" Text="{Binding Path=PersonData.Age, Mode=TwoWay}" /> <sdk:Label Height="25" Grid.Row="9" Grid.Column="0" HorizontalAlignment="Right" Name="label5" VerticalAlignment="Center" Width="120" Content="Address :" /> <TextBox Height="25" Grid.Row="9" Grid.Column="1" HorizontalAlignment="Left" Name="txtAddress" VerticalAlignment="Top" Width="200" Text="{Binding Path=PersonData.Address, Mode=TwoWay}" /> </Grid> </UserControl>
Now if all the things are working correctly you can run the application. And you will see the nice interface without having exceptions.
You can download the source code from here for this example : Download Here