Model View ViewModel (MVVM)
1)
Introduction
2)
What's the difference between MVVM, MVP
and MVC?
2.1) MVC - Model-View-Controller:-
2.2) MVP -
Model-View-Presenter
2.3) MVVM -
Model-View-ViewModel
3)
DataModel
4)
ViewModel
5)
View
6)
Code
Snippet
7)
Separation
of logic and presentation
8)
How
the MVVM pattern became convenient
9)
Advantages
of MVVM
10) Some MVVM Frameworks
1) Introduction:-
The Model
View ViewModel (MVVM) sometimes called
DataModel-View-ViewModel is
an architectural pattern Very similar to Martin Fowler’s “Presentation Model”.
It is first published by John Gossman of MSFT, Dan
Crevier of MSFT wrote a multi-part series for MVVM.
MVVM is
targeted at modern UI development platforms (Windows Presentation Foundation or
WPF, and Silverlight).
2) What's
the difference between MVVM, MVP and MVC?
2.1) MVC - Model-View-Controller:-
MVC is a
well-established pattern made up of the “Mediator” and the “Observer”
patterns. The MVC pattern consists of
one controller that directly gets all user input. Depending of the kind of
input, he shows up a different view or modifies the data in the model. The view
sits at the top of the architecture. The controller sits below the view. The
model sits below the controller. The model and the view are created by the
controller. The view only knows about the model, but the model does not know
about any other objects.
2.2)
MVP - Model-View-Presenter
In the MVP
pattern, controller is replaced with a presenter. The view gets the user input
and forwards it to the presenter. The presenter than modifies the view or the
model depending on the type of user action. The view and the presenter are
tightly coupled. There is a bidirectional one-to-one relation between them. The
model does not know about the presenter. The view itself is passive, that’s why
it's called presenter pattern, since the presenter pushes the data into the
view. This pattern is often seen in Win Forms and early WPF applications.
2.3)
MVVM - Model-View-ViewModel
The
model-view-viewmodel is a typically WPF pattern. The controller is replaced
with a view model. The view model sits below the UI layer that gets all the
user input and forwards it to the viewmodel. The view model exposes the data
and command objects that the view needs. The view actively pulls the data from
the viewmodel by using databinding. The model does not know about the view
model.
Basic diagram
Detail Diagram
3) DataModel
DataModel is
responsible for exposing data in a way that is easily consumable by WPF. All of
its public APIs must be called on the UI thread only. It must implement
INotifyPropertyChanged and/or INotifyCollectionChanged as appropriate. When
data is expensive to fetch, it abstracts away the expensive operations, never
blocking the UI thread. It also keeps the data “live” and can be used to
combine data from multiple sources. These sorts of classes are fairly
straightforward to unit test.
The lines
between DataModels and ViewModels can be blurry. DataModels are often shown in
the UI with some DataTemplate, which isn’t really so different than the way we
use ViewModels. However, the distinction usually makes sense in practice. I
also want to point out that there’s often composition at many layers.
ViewModels may compose other ViewModels and DataModels. And, DataModels may be
composed of other DataModels.
4) ViewModel
A ViewModel
is a model for a view in the application. It exposes data relevant to the view
and exposes the behaviors for the views, usually with Commands. The model is
fairly specific to a view in the application, but does not subclass from any
WPF classes or make assumptions about the UI that will be bound to it. Since
they are separate from the actual UI, these classes are also relatively
straightforward to unit test.
The
ViewModel is a model of the view. That means: You want to DataBind a property
from
your DataObject (model) to a property from your ViewObject (view) but you sometimes cannot bind directly to a CLR property of the model (because of converting or calculating). This is when ViewModel comes into play. It propagates the already calculated or converted value from your model, so you can bind this property directly to the view property.
your DataObject (model) to a property from your ViewObject (view) but you sometimes cannot bind directly to a CLR property of the model (because of converting or calculating). This is when ViewModel comes into play. It propagates the already calculated or converted value from your model, so you can bind this property directly to the view property.
5) View
A View is
the actual UI behind a view in the application. The pattern we use is to set
the DataContext of a view to its ViewModel. This makes it easy to get to the
ViewModel through binding. It also matches the DataTemplate/Data pattern of
WPF. Ideally, the view can be implemented purely as Xaml with no code behind.
The attached property trick comes in very handy for this.
The main
thrust of the Model/View/ViewModel architecture seems to be that on top of the
data (“the Model”), there’s another layer of non-visual components (“the
ViewModel”) that map the concepts of the data more closely to the concepts of
the view of the data (“the View”). It’s the ViewModel that the View binds to,
not the Model directly.
6) Code Snippet:-
View:-
<Window x:Class="WpfSimple.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfSimple"
Title="MainWindow" Height="150" Width="370">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Button Content="Click"
Height="23"
HorizontalAlignment="Left"
Margin="77,45,0,0"
Name="btnClick"
VerticalAlignment="Top"
Width="203"
Command="{Binding ButtonCommand}"
CommandParameter="Hai" />
</Grid>
</Window>
The ViewModel :-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
namespace WpfSimple
{
class MainWindowViewModel
{
private
ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return
m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
}
}
public
MainWindowViewModel()
{
ButtonCommand=new RelayCommand(new Action<object>(ShowMessage));
}
public void ShowMessage(object
obj)
{
MessageBox.Show(obj.ToString());
}
}
}
RelayCommand
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
namespace WpfSimple
{
class RelayCommand : ICommand
{
private
Action<object>
_action;
public
RelayCommand(Action<object> action)
{
_action = action;
}
#region ICommand Members
public bool CanExecute(object
parameter)
{
return
true;
}
public event EventHandler
CanExecuteChanged;
public void Execute(object
parameter)
{
if (parameter
!= null)
{
_action(parameter);
}
else
{
_action("Hello World");
}
}
#endregion
}
}
INotifyPropertyChanged
public class Product:INotifyPropertyChanged
{
private int m_ID;
private string m_Name;
private double m_Price;
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void
OnPropertyChanged(string propertyName)
{
if
(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public int ID
{
get
{
return
m_ID;
}
set
{
m_ID = value;
OnPropertyChanged("ID");
}
}
public string Name
{
get
{
return
m_Name;
}
set
{
m_Name = value;
OnPropertyChanged("Name");
}
}
public double Price
{
get
{
return
m_Price;
}
set
{
m_Price = value;
OnPropertyChanged("Price");
}
}
}
class ProductViewModel
{
private IList<Product>
m_Products;
public
ProductViewModel()
{
m_Products = new
List<Product>
{
new
Product {ID=1, Name ="Pro1", Price=10},
new
Product{ID=2, Name="BAse2",
Price=12}
};
}
public IList<Product>
Products
{
get
{
return
m_Products;
}
set
{
m_Products = value;
}
}
private ICommand mUpdater;
public ICommand UpdateCommand
{
get
{
if
(mUpdater == null)
mUpdater = new Updater();
return
mUpdater;
}
set
{
mUpdater = value;
}
}
private class Updater : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
}
#endregion
}
}
Main Window (View)
<Window x:Class="WpfMvvmTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Height="314">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView Name="ListViewEmployeeDetails" Grid.Row="1" Margin="4,109,12,23" ItemsSource="{Binding Products}" >
<ListView.View>
<GridView x:Name="grdTest">
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" Width="100"/>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="100" />
<GridViewColumn Header="Price" DisplayMemberBinding="{Binding Price}" Width="100" />
</GridView>
</ListView.View>
</ListView>
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="
Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.ID}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Name}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" Name="txtPrice" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Price}" />
<Label Content="ID" Grid.Row="1" HorizontalAlignment="Left" Margin="12,12,0,274" Name="label1" />
<Label Content="Price" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,59,0,0" Name="label2" VerticalAlignment="Top" />
<Label Content="Name" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,35,0,0" Name="label3" VerticalAlignment="Top" />
<Button Content="Update" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="310,40,0,0" Name="btnUpdate"
VerticalAlignment="Top" Width="141"
Command="{Binding Path=UpdateCommad}"
/>
</Grid>
</Window>
7) Separation of logic and presentation: -
The MVVM pattern is so far only a
convenient way to bind data to the view. But what about user actions, how are
they handled? The classic approach, known from WinForms is to register an event
handler that is implemented in the code-behind file of the view. Doing this has
some disadvantages:
Having event
handlers in the code-behind is bad for testing, since you cannot mock away the
view.
Changing the
design of the view often also requires changes in the code, since every element
has its different event handlers.
The logic is
tightly bound to the view. It's not possible to reuse the logic in another view
So the idea
is to move the whole presentation logic to the view model by using another
feature of WPF, namely Commands. Commands can be bound like data and are
supported by many elements as buttons, togglebuttons, menuitems, checkboxes and
inputbindings. The goal here is not to have any line of logic in the
code-behind of a view.
8) How the MVVM pattern became convenient
WPF has a
very powerful databinding feature that provides an easy one-way or two-way
synchronization of properties. You can directly bind two WPF elements together,
but the common use of databinding is to bind some kind of data to the view.
This is done by using the
DataContext
property. Since the DataContext
property is marked as inherited, it
can be set on the root element of a view and its value is inherited to all
subjacent elements of the view.
One big
limitation of using the
DataContext
property as data source is, that
there is only one of it. But in a real life project you usually have more than
one data object per view. So what can we do? The most obvious approach is to aggregate
all data objects into one single object that exposes the aggregated data as
properties and that can be bound to the DataContext
. This object is called the view
model.
9) Advantages of MVVM :-
The view-model can
easily be tested by using standard unit-tests (instead of UI-testing)
The view can be
redesigned without changing the viewmodel, because the interface stays the
same.
The view-model can
even be reused, in some special cases (this is usually not recommended)
10) Some MVVM Frameworks
PRISM
(Microsoft)
MVVM Light
(Laurent Bugnion)
WPF
Application Framework
Chinch
Caliburn
Micro
Onyx
nRoute
MVVM
Foundation
10.1) Prism:-
Prism (or
Composite WPF) is a framework provided by Microsoft to help build composite WPF
and Silverlight applications. It has mechanisms for UI composition, module
management and dependency injection. Prism itself is modular, so you can pick
and choose the parts of it that are relevant to your application.
10.2) MVVM Light
(Laurent Bugnion)
Like other
MVVM implementations, the toolkit helps you to separate your View from your
Model which creates applications that are cleaner and easier to maintain and
extend. It also creates testable applications and allows you to have a much
thinner user interface layer.
10.3) WPF Application
Framework
The WPF
Application Framework (WAF) is a lightweight Framework that helps you to create
well-structured WPF Applications. It supports you in applying a Layered
Architecture and the Model-View-ViewModel (aka MVVM, M-V-VM, PresentationModel)
pattern.
For more
information about WAF see http://waf.codeplex.com/
10.4) Chinch
Cinch is a
framework that gives a number of helper classes to allow the developer to
quickly get to grips with creating scalable testable MVVM frameworks as quickly
as possible.
For more
information about Chinch see http://cinch.codeplex.com/
10.5) Caliburn Micro
It
implements a variety of UI patterns for solving real-world problems. Patterns
that are highlighted include MVVM (Presentation Model), MVP and MVC
For more
information about Caliburn Micro see
http://caliburnmicro.codeplex.com/
10.6) Onyx
Onyx
provides a framework that aids in the creation of WPF applications that follow
the Model-View-ViewModel design pattern. The goal when developing with Onyx is
to create XAML based Views that have no code in the codebehind file (remember,
this is a goal, not a requirement, and one should be pragmatic). In addition,
the ViewModel should contain no code that ties it to any specific UI or UI
features that are not easily unit tested.
For more
information about Onyx see http://wpfonyx.codeplex.com/
10.7) nRoute
nRoute is a
composite application framework for creating MVVM-style applications in
Silverlight, WPF, and Windows Phone 7
For more
information about nRoute see http://nroute.codeplex.com/
10.8) MVVM Foundation
MVVM
Foundation is a library of classes that are very useful when building
applications based on the Model-View-ViewModel philosophy. The library is small
and concentrated on providing only the most indispensable tools needed by most
MVVM application developers
For more
information about MVVM Foundation see http://mvvmfoundation.codeplex.com/