2. Overview
• A bit about my experience of MVVM.
• What problems adopting MVVM addresses.
• An overview of the MVVM pattern.
• Adopting MVVM.
• A simple example.
5. Typical Development Problems
• Tightly coupled brittle code that is difficult to
maintain and extend.
• It can be difficult to separate UI state and
logic from the UI presentation.
• Difficult to test UI state and logic.
• The designer is tied to the UI components
written by the developer.
6. MVVM …
• Tightly coupled brittle code that is difficult to
maintain and extend.
• It can be difficult to separate UI state and
logic from the UI presentation.
• Difficult to test UI state and logic.
• The designer is tied to the UI components
written by the developer.
7. Separation of Concerns
• View – UI Layout & User Interaction
• View Model – UI State and Logic
• Model – Business Logic and Data
10. Developer Designer Workflow
• Designer has freedom to design.
• Designer can work independently.
• Designer does not need to touch code.
• Designer can create design time sample data.
12. MVVM View
• The View defines the structure and appearance of the UI.
• The View’s DataContext is a View Model.
• Minimal, if any, code behind.
• View updated by notification events from the View Model.
• UI Gestures are passed to the View Model, usually via
Commands.
13. MVVM View Model
• The View Model is responsible for UI logic, data and state.
• The View Model exposes bindable properties.
• The View Model exposes ICommand properties for UI
controls with Command properties.
• The View Model exposes public methods that can be invoked
by the View.
• The View Model is completely testable.
14. MVVM Model
• The Model is responsible for business logic and data, the
client side Domain Model.
• The Model can expose bindable properties for use by the
View directly or via the View Model as an Adapter.
• Model objects can implement IDataErrorInfo to provide the
View with validation state information.
15. MVVM Commands
• Invoked in the View by user interaction.
• Bound to ICommand properties in the View Model.
• Differ from WPF Routed Commands as they are not
delivered via the UI logical tree. Equally, Routed Commands
will not get delivered to the View Model as it is outside the
UI logical tree.
16. Data Validation / Error Reporting
• Implement IDataErrorInfo or INotifyDataErrorInfo in View
Model and Model classes.
• IDataErrorInfo – presents basic indexed error information.
• INotifyDataErrorInfo – presents multiple errors per property,
asynchronous data validation and notification of error state
changes (In WPF 4/ Silverlight 4).
18. A Typical MVVM Application
Order of
Construction Dependency
Injection
Param-less
Contructors
D:DataContext
d:DesignSource Objects or
Methods
IDateErrorInfo
INotifyDataErrorInfo
19. Construction and Wire Up
• One-to-One loosely coupled relationship between View and
View Model.
• Create View as a Data Template.
– The View Model is instantiated first.
– Data Templates are lightweight and flexible.
– No code behind is available for Data Templates.
20. Construction and Wire Up
• Create the View Model in the View’s XAML.
– Requires a parameterless ctor in the View Model.
– Works well in design tools.
– The View must have knowledge of the View Model type.
• Instantiate the View Model in the View’s code behind.
– The View must have knowledge of the View Model type.
– Loose coupling can be achieved by use of a dependency
injection container such as Unity.
21. Provision of Design Time Data
• Expression Blend XML Sample Data.
– Simple to create in Blend.
– Not rendered in Visual Studio.
– Sample data not compiled in, but schema is.
• XAML Sample Data.
– Uses d:DesignData XAML markup extension.
– Supported in Blend 4 and VS2010.
– XAML sample data is not compiled into assemblies.
22. Provision of Design Time Data
• XAML Resource.
– Provide a simple resource instantiating desired types.
– Useful for quick throw away data when editing a
template.
• Code.
– Uses d:DataContext and d:DesignInstance XAML markup
extensions.
– May need to be maintained by developers.
23. Key Decisions
• Construct Views or View Models first and use of a
dependency injection container.
• Expose Commands from the View Model as
Command objects or Command methods.
• Use of IDataErrorInfo / INotifyDataErrorInfo.
• Provision of design time data for use in Expression
Blend.
27. Pre MVVM
private void MediaList_MouseDoubleClick( object sender,
MouseButtonEventArgs e)
{
MediaFile mediaFile = MediaList.SelectedItem as MediaFile;
if (mediaFile != null)
{
_mediaFolder.Play(mediaFile);
CurrentItem.DataContext = mediaFile;
}
}
UI Interactions implemented as code behind
<Application x:Class="WpfMediaPlayer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
Bootstrapping – StartupUri for App
_mediaFolder.Load(this.MediaFolderPath.Text);
this.MediaList.ItemsSource = _mediaFolder.MediaFiles;
UI Binding to MediaFile Properties
28. Pre MVVM - Comments
• Low Concept Count…. It is a simple app after all!
• Minimal code required for implementation.
• Testability - All UI logic and state is implemented as
code behind and is difficult to test.
• Coupling - The MainWindow class needs knowledge
of the data types.
• Extensibility / Maintainability – Code rapidly
becomes complex and potentially confusing as new
UI features are added.
29. MVVM
Separate View Components in UI
Bootstrapping – Dependency Injection
Implement View Models
Decouple View Models and Model
Bindable Properties
Command Properties
33. MVVM View Components
• A little excessive for a small app?
• Extensible – We can easily extend the individual
Views if we wish without affecting the other views.
• Implement Views as Data templates
36. MVVM View Model Components
• Decoupling UI actions using Commands.
• NowPlayingViewModel provides an adapter for the
IMediaFile.
• Other Views bind directly to IMediaFile.
• UI behaviour is now completely testable as there is
no code behind any of the Views.
38. MVVM Bootstrapping
protected override void OnStartup(StartupEventArgs e)
{
using (IUnityContainer container = new UnityContainer())
{
// register models
container.RegisterType<IMediaFolder, MediaFolder>
(new ContainerControlledLifetimeManager());
// register view models
container.RegisterType<ISelectedDirectoryViewModel, SelectedDirectoryViewModel>
(new ContainerControlledLifetimeManager());
container.RegisterType<IMediaListViewModel, MediaListViewModel>
(new ContainerControlledLifetimeManager());
container.RegisterType<INowPlayingViewModel, NowPlayingViewModel>
(new ContainerControlledLifetimeManager());
MainWindow window = container.Resolve<MainWindow>();
window.SelectedDirectoryView.DataContext =
container.Resolve<ISelectedDirectoryViewModel>();
window.MediaListView.DataContext = container.Resolve<IMediaListViewModel>();
window.NowPlayingView.DataContext = container.Resolve<INowPlayingViewModel>();
window.Show();
}
}
App.xaml.cs
39. MVVM - Comments
• Testability – UI Logic and state is independent of UI
layout.
• The layers have been successfully decoupled to
assist in independent testing and development of
components.
• The code is potentially simpler to extend into a
larger application and will be simpler to maintain.
• High Concept Count, especially for a simple app.
40. Summary
• The MVVM pattern is well suited for WPF /
Silverlight development.
• Adopting MVVM can improve maintainability.
• Adopting MVVM can improve quality.
• Adopting MVVM frees up designer creativity.
• Adopting MVVM can improve the product.
Hi, my name’s John Cumming. I work for CM Group in the UK as a WPF engineer. I’ve put this presentation together to introduce the Model View View Model, or MVVM pattern. If you are familiar with developing WPF applications, you should find this fairly straightforward to follow.
I don’t intend to cover a large amount of detail today, but I would like to introduce my background in WPF before looking at problems that MVVM addresses as well as an overview of the MVVM pattern itself. After that we shall look the practical issues of adopting MVVM and a simple worked example.
Firstly, my experience of MVVM. Well, I won’t pretend to have extensive experience of it, but I did work on a large media player project at Nokia where we adopted the MVVM pattern 3 years ago, very early in its development. We certainly didn’t implement it perfectly, mainly because we didn’t understand it fully and introduced all the kind of problems that MVVM was intended to solve. So hopefully this presentation will give a good overview that perhaps I missed and enable you to understand MVVM a little better.
Firstly then, lets look at some typical development problems that MVVM helps us address.
Here are some typical desktop application development problems. Firstly, there is a tendency, if not designed correctly, for software to become tightly coupled and brittle, making maintenance and extension difficult. It is also very easy to combine UI state, logic and presentation in Controls. These two problems combine, along with others, to make code that is very difficult to test. It also makes it difficult for designers to work on making the product look good as they are tied to UI controls written by the developer.
SO how does MVVM Address this? We’re going to look at several ways to address these problems. MVVM encourages Separation of Concerns, allowing for loosely coupled code. MVVM also turns out to be a very natural pattern for developing in XAML. All of this increases testability and also helps with the designer developer workflow as we shall see.
MVVM encourages Separation of Concerns by splitting the app into three layers, The View which is responsible for UI Layout and Interaction, The View Model, which is responsible for UI State and Logic and the Model which is responsible for Business Logic and Data.
MVVM is also a Natural XAML pattern as it makes good use of Data Binding for displaying information to the user and Commands for executing user actions.
The separation of UI Logic and state allows for increased testability. In fact, John Gossman a WPF architect at Microsoft said that a litmus test for MVVM is that you can run the application from within unit tests.
Also, the separation of UI Layout and interaction allows the designer to have freedom and independence in designing the look and feel of the application. The designer need not worry about code and can create any sample data they need at design time.
So now that we have taken a brief look at the kind of problems MVVM addresses, lets have an overview of the pattern itself.
We shall take a look at the layers first. The View is what defines the structure and appearance of the UI, binding to a View model for data and behavior. There should be minimal, if any, code behind. The View is updated by notification events from the View Model and all UI gestures are passed to the View Model via Commands, rather than being handled by mouse click events, for example.
The View Model layer is responsible for UI logic state and data, exposing bindable properties, including Commands that the View can use. By doing this, we separate the View Model from any specific UI technology and allow the UI logic and state to be completely testable.
The Model in MVVM is the client side Domain Model, the business logic and data. It can also expose bindable properties for use by the view directly or via the View Model. Model objects can also implement Error Info interfaces to provide the view with validation state information.
Commands are used to invoke operations by the View. They are bound to ICommand properties in the View Model. They can also be implemented by Command methods on the View Model. The differ from WPF Routed commands as they are not delivered via the logical tree, but deliver directly to the view model, which is outside the logical tree.
We can provide Data Validation and Error reporting via the IDataErrorInfo interface, or, if we are using WPF 4 or Silverlight 4, the INotifyDataErrorInfo interface which is a more flexible interface to use.
Right, that’s the theory, which is all well and good, but we need to know how to adopt and implement MVVM, which is what we shall now move on to now.
Now here is a typical MVVM Application and I shall go through some areas we need to look at including what support, if any, we need to provide for Design Time Data. Also how are we going to wire everything up once we have created the various components. Also exposing commands, how are we going to implement that. And as I said earlier, what support do we want to provide for Error Reporting.
Firstly then, some things we need to consider when constructing our application and wiring up the component parts. We need to maintain a One to one loosely coupled relationship with the View and View Model. We should also decide how we implement the Views as we can use a User Control or just a data template, either way it is best to take a consistent approach in the application. If we construct a view as a data template we must construct the view model first. Data templates are lightweight and flexible but do not provide the ability to write code behind.
We can just create an instance of the view model in the Views XAML, which requires the View Model to have a parameterless constructor, which is not always ideal. However this method of creating the view model works well in integrating with design tools. However the View must have knowledge of the View Model, which may be undesirable. Another way would be to instantiate a view model in the View’s code behind and maybe achieve loose coupling by using a dependency injection container, which we shall come to when we go through a worked example.
There are also various means of providing design time data. I shall pass over these quickly as this area is not one I am well versed in, but various ways include Blend XML Sample Data, XAML sample data that is supported in Blend 4 and VS2010.
It can also be provcided as a XAML resource, as code maintained by developers for the designer.
So to summarise, here are some key decisions we need to make when adopting MVVM, and it is generally a good practice to take a consistent approach through the application. How are we going to construct and wire up our Views and View Models? How are we going to expose commands from the view model? Shall we implement the Error Info interfaces ? And how are we going to provide design time data support.
I always find the best way to understand a technology or pattern is to work on implementing a simple application using it. Although the example is very simple and MVVM is a little bit of an overkill for it, I have written a very small media player application both as a kind of pre-MVVM version and an MVVM version. The project files should be easy to download from my blog at sputnikdev.wordpress.com.
Another great source, one which I have to say I’ve taken some ideas from is Karl Shifflet’s In The Box MVVM training which can be found on his blog. I would recommend going through this as it has far more material than this presentation has and does not take too long to go through. But for now, on with our sample application. I would advise that you have the visual studio application open if you can.
Here is my wonderful media player. WMP watch out! The user can simply browse for a folder containing media, view the list of media in the folder, with some meta data displayed and double click to play the media. The current track is then displayed in the foot of the window and a small button allows the user to pause and resume the playback of the selected track.
I will not go through the code in detail, as I am assuming you are familiar with WPF. The application is a simple single window application, with all UI state and behaviour implemented as code behind in the MainWindow class, responding to user interaction events. However, there is some binding to a data layer through the MediaFile class, so there are already hints as to how this could be re written using MVVM as a pattern.
Some comments about this approach. The concept count is low, after all it is a very simple application. There is also minimal code … at this stage. Some negative comments might be that the UI logic and state is virtually untestable and the MainWindow class is tightly coupled to the Data Types. Although there is minimal code at this stage, as the application develops, the code may have a tendency to get more complex and potentially confusing as new features are added. Extensibility and Maintainability will no doubt take a hit further down the line.
So how are we going to go about improving the situation. Some things we need to do to improve matters are as follows. We shall take a look at wire up using dependency injection, we shall separate the View into components and implement view models with bindable properties including Commands. We shall also decouple the view model and model.
I have split the UI into three components as follows. A bit excessive again for a window with so few controls, but it allows us to extend it easily in the future.
Here is the mainwindow XAML code.
As I said earlier, although a little excessive, we are now in a good position to extend the application. I chose to implement the views as data templates due to the lightweight and codeless nature of data templates.
We are going to maintain a one to one relationship between the views and view models.
We have now decoupled the UI actions using Commands. The NowPlayingViewModel acts as an adapter between the View and Model where other views bind directly to IMediaFile. The UI behaviour and state is now completely testable, in isolation from both the UI layout and the data model. This is achieved through some changes to the Model and dependency injection as we shall see now.
The Model now has some simple interfaces defined, allowing us to mock the model for testing the View Model.
And dependency injection is achieved via the Unity framework
Our MVVM solution has increased testability as layers have been successfully decoupled. The code is potentially simpler to extend into a larger application and will be easier to maintain over time. However, the concept count has gone up, especially for what is currently such a simple application.
So we have seen that the MVVM pattern is very well suited for WPF development. It is also very well suited for Silverlight as a result. We can improve maintainability of code as well as quality. We can free up the designers creativity. Hopefully I have shown you how adopting MVVM can improve the product.
If you have any questions, please feel free to comment on my blog at sputnikdev.wordpress.com