MVVM
The model-view-viewmodel is a typically WPF pattern. It consists of a view that
gets all the user input and forwards it to the viewmodel, typically by using
commands. The view actively pulls the data from the viewmodel by using data
binding. The model doesn’t know about the ViewModel and the ViewModel doesn’t
know about the View.
Explaining MVVM through an example
Let’s create a sample Patient Management Application using MVVM. Going step by
step we must first define our Model, then define the ViewModel and finally the
View.
Step 1 - Creating the Model:
Def: The Model is often referred to as Domain Model, completely UI
independent that stores the state and helps in the processing of the problem
domain.
In our example Model becomes the DOM object which is nothing
but the patient entity. The sample below shows the patient Entity.
public class Patient
{
public int Id { get; set; }
public string Name { get; set; }
public Int64 MobileNumber { get; set; }
}
Step 2 – Creating the View Model
Def : The term means “Model of a View”, and can be thought of as abstraction
of the view, but it also provides a specialization of the Model that the View
can use for data-binding. In this latter role the ViewModel contains
data-transformers that convert Model types into View types, and it contains
Commands the View can use to interact with the Model. The ViewModel has been likened
to a conceptual state of the data as opposed to the real state of the data in
the Model.
Coming back to our example lets create the PatientViewModel which will expose
the Properties(which contains the Data) and Commands (User actions) which will
be binded to the view.
Public Properties :
All the data that needs to be binded to the View will be exposed as public
properties. The View Model will implement PropertyChanged Event so that the
view will be updated automatically whenever there is a change in the ViewModel.
To do this we are triggering the PropertyChanged event when the property is
set.
public class PatientDetailViewModel: INotifyPropertyChanged
{
public int Id
{
get { return domObject.Id; }
set
{
domObject.Id = value;
OnPropertyChanged("Id");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Commands :
Def : The main idea is to move the whole presentation logic to the view
model. This can be attained by using another feature of WPF, namely Commands.
Commands can be bound like data and are supported by many elements as buttons,
toggle buttons, menu items, checkboxes and input bindings. The goal here is not
to have any line of logic in the code-behind of a view.
The View will execute commands on user action and the commands will be
implemented in the ViewModel. To do this, you can’t use the standard WPF
RoutedUIEvent, but you can easily develop your own command classes. A common
way to do this is to create a command object that calls a delegate you specify.
Here is an example of how you can define a custom command class which you will
later use when you are defining the commands in the ViewModel.
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null){}
public RelayCommand(Action<object> execute,
Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
Coming back to our example, our sample app requires Add, Delete &
Search functionalities. The sample shows how to implement Add command using the
RelayCommand that we defined above.
public class PatientDetailViewModel: INotifyPropertyChanged
{
public ICommand AddPatientCmd { get { return _addPatientCmd; } }
public PatientDetailViewModel()
{
_addPatientCmd = new RelayCommand(Add, CanAdd);
}
public bool CanAdd(object obj) { public void Add(object obj) { }
Step 3 – Creating the View
Def : A View is defined in XAML and should not have any logic in the
code-behind. It binds to the view-model by only using data binding. The view
involves mostly just setting up the UI and bindings to the ViewModel. The
DataContext property for this control will be set to the ViewModel.
As we have created the PatientViewModel all we need to do is create the
PatientDetailView and then bind the ViewModel as the DataContext. The Sample
here shows Property binding and Command binding.
<UserControl ...>
<!--Bind the View Model to the View. -->
<UserControl.DataContext>
<ViewModels:PatientDetailViewModel/>
</UserControl.DataContext>
....
<TextBox Name="TbxName" ....
Text="{Binding Path=Name}"/>
....
<Button Name="BtnAdd" Content="Add" ....
Command="{Binding AddPatientCmd}"/>
.....
</UserControl>
Points to Note
Since in a real life project you usually have more than one data object per
view, using a view model becomes convenient since you can aggregate all data
objects into one single View Model that
exposes the aggregated data as properties and that can be bound to the
DataContext.
The key point to MVVM is to make the
view completely concerned with how data looks, never about behavior. Ideally, a
view should be completely plug-and-play, with the only work being to hook up
the bindings to the ViewModel.
In addition, separating all the behavior from the GUI allows you to be far more
complete in unit testing.