MVVM Technical Description

This is an excerpt from, In the Box – MVVM Training that is posted on the Visual Studio Gallery.

Have a great day,

Karl


The gold standard for learning and describing design patterns is the book, Design Patterns: Elements of Reusable Object-Oriented Software.

Below, I present the MVVM pattern using the chapter format, section titles defined in the book.


Model-View-ViewModel

UI Design


Intent

Provide a clean separation of concerns between the user interface controls and their logic.

Also Known As

MVVM, M-V-VM and ViewModel

Motivation

Development languages like Visual Basic (1-6), Microsoft Access, .NET Windows Forms, WPF, Silverlight and Windows Phone 7 provide a default experience that leads a developer down the path of dragging controls from a Toolbox to a design surface then writing code in the form's code-behind file. Many software companies and consultants have successfully delivered applications authored using these languages to customers.

As these applications grew in size and scope and were modified over-time, complex maintenance issues began to surface. Some of these issues were limitations of the language; others resulted from the lack of supporting infrastructure like source control or test frameworks. Some were the result of application logic being located in code-behind files and the resulting tight coupling between the UI form controls and the code-behind that increased the cost to make form modifications.

The four top reasons for using the MVVM pattern in Microsoft XAML applications are:

  • Provides separation of concerns
  • It is natural pattern for XAML platforms
  • Enables the developer-designer workflow
  • Increases application testability

Customer Maintenance Form Scenario

Let's quickly examine a common scenario found in forms over data applications and see how the MVVM pattern is used.

Our application requires a data entry form that allows a customer entity to be displayed, saved and or deleted.

The MVVM pattern addresses separation of concerns by defining that UI application logic be located in a view model class as opposed to the view's code-behind file. It leverages the rich data binding stack of the XAML platform to expose the view model to the view's UI controls through the view's DataContext property. A by-product of the separation of concerns is the enablement of a clean developer-designer workflow. Designers are now emancipated to modify the UI, change or rename controls to suite their requirements without breaking the application. Application testability has been increased because the view model takes its dependencies in the form interfaces, allowing the view model to be individually tested in isolation.

alt

The above UML diagram shows:

  • CustomerView.DataContext is CustomerViewModel
  • CustomerViewModel exposes a Customer property to the View

CustomerViewModel exposes two ICommand properties that the view's UI controls which support commands can bind to

  • CusomverViewModel has its dependencies injected in the constructor
  • CustomerViewModel private data operation methods call public methods exposed on the ICustomerRespository interface

Applicability

Use the MVVM pattern when developing on Microsoft XAML platforms.

Structure

Components communicate through data bindings and event notification. Additionally, the view can use behaviors to invoke public methods on the view model.

alt

The model is depicted as an entity and the application domain.

alt

Participants

  • Model
    • Responsible is for business logic and data. The model is your client side domain and is represented as data entities, business objects, repositories and services
    • Implements change notification for properties and collections
    • Can implement validation interfaces such as IDataErrorInfo so that validation errors can be surfaced on the view
  • View
    • Defines structure, appearance and interactivity of the user interface
    • Implemented as a Window, UserControl, Page, DataTemplate, or custom control
    • Can be the applications top-level control, a sub-component of a parent view or a DataTemplate for an object in an ItemsControl.
    • Has little or no code-behind
    • DataContext is a view model
    • Controls data bind to view model public properties
    • Behaviors can invoke view model public methods
  • View Model
    • Responsible for UI logic and data for the view.
    • Provides a layer of abstraction between the view and the application domain or model
    • Can play the role of an adapter between the view and the model when required
    • Can expose ICommand properties that view Command properties can data bind to
      • Note: behaviors can also data bind to an ICommand property
    • Can expose public methods that view behaviors can invoke
    • Maintains state for the view. State changes are communicated to the view via data bindings.
    • Implements change notification for properties and collections

Collaborations

The view model is the view's DataContext.

Consequences

The MVVM pattern has the following benefits and liabilities:

  1. Promotes separation of concerns. The MVVM pattern helps you keep a clean separation of concerns by moving UI logic from a view code-behind to a separate view model class. The result is components that are loosely coupled and can be modified in isolation making the application easier to evolve and maintain over time.
  2. Enables the developer-designer workflow. Developers can now be less territorial with their views because changes in the XAML won't break the UI logic in the view model. Designers are liberated to be expressive and creative as they use tools like Expression Blend to create modern interactive applications without worrying about breaking the view when they make changes to it.
  3. Improves testability. By moving UI logic to a separate class that UI logic can test tested in isolation. The unit tests execute much faster because UI Automation is not required, which can motivate developers to write more tests and run the tests more often.
  4. View models without empty a constructor cannot be instantiated in XAML. Most view models take arguments in their constructor; these represent the view model's dependencies. View models without a default empty constructor cannot be instantiated in XAML; which requires an alternate wiring strategy.
  5. Requires wiring up the view and view model. Implementing the MVVM pattern requires additional work over using the view and corresponding code-behind. Developers need to instantiate a view model and assign it to the view DataContext property. Perhaps in the future, Microsoft will provide out-of-the-box strategies for wiring up views and view models.
  6. Enabling designer tooling can require d: designer properties. If the view has no design-time knowledge of the view model, the designer tooling will not be able to determine the shape of its DataContext; which neuters the data binding builder. In order to provide a design-time shape to the designer tooling, the developer or designer needs to set the d:DataContext or d:DesignSource properties to set a design-time DataContext.

Implementation

Consider the following when implementing the MVVM pattern:

  1. Wiring strategies. Wiring strategy refers to a technique for connecting the view and view model at run-time. The selected wiring strategy is typically tied to the application's strategy for dependency resolution; for example an IOC container, MEF or a Service Locator. Wiring strategies can be implemented in XAML, code-behind, IOC container extension, screen conductor or coordinator. How view model dependencies are resolved reflects on the available wiring strategy choices.
  2. Commands, behaviors or convention. There are several techniques for view controls to communicate UI gestures so that view mode code can be executed. Developers need to choose whether to expose public ICommand properties or public methods on their view models. The view controls can then data binding to the ICommand properties or can use behaviors to invoke methods on the view model. Additionally, a screen conductor or coordinator or IOC container extension can employ a convention technique to wire up the UI controls to their view model counterparts.
  3. Design-time Sample Data. Evaluate the various strategies for displaying sample data and determine the most appropriate technique.Design-time sample data can be surfaced on the UI using the d:DesignData markup extension, d:DesignInstance markup extension or can be emitted by the view model implementing a design-time repository that returns sample data dynamically created in code or loaded from a file. Not all views require sample data, for the ones that do, provide good rich sample data for your designer.
  4. Enable designer tooling. In order for the designer tooling to provide maximum benefit to both developers and designers, the tooling must be able to determine the shape of the DataContext. If the view has no design-time knowledge of the view model either through the view model being instantiated in XAML or through sample data being applied, the designer tooling will not be able to determine the shape of its DataContext; which neuters the data binding builder. In order to provide a design-time shape to the designer tooling, the developer or designer needs to use the d:DataContext or d:DesignSource properties to set a design-time DataContext.

Sample Code

The below XAML snippet shows wiring up the view model in XAML. Remember, view models wired up like this must have a default empty constructor.

 <Window 
    xmlns:local="clr-namespace:Acme.MVVM"  
    x:Class="Acme.MVVM.MainWindow">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>

The below PublisherView shows how property injection can be used to wire up the view model.

 public partial class PublisherView : UserControl {

    [Dependency]
    public PublisherViewModel ViewModel {
        get { return this.DataContext as PublisherViewModel; }
        set { this.DataContext = value; }
    }

    public PublisherView() {
        InitializeComponent();
    }
}

The below App class shows how a view model is added to a view during construction. This sample pattern can also be automated by authoring an IOC container extension to create the view and view model combination and wire them up as illustrated below.

 public partial class App : Application {

    protected override void OnStartup(StartupEventArgs e) {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<IDialogService, ModalDialogService>(
            new ContainerControlledLifetimeManager());
        
        container.RegisterType<IEventRepository, EventRepository>(
            new ContainerControlledLifetimeManager());

        MainWindow window = container.Resolve<MainWindow>();
        window.DataContext = container.Resolve<MainWindowViewModel>();
        window.Show();
    }
}

The below XAML snippet shows the view Button controls binding to properties on their DataContext. The C# code snippet shows the ICommand properties that the view is binding to.

 <StackPanel Orientation="Horizontal" Grid.Row="5" Grid.ColumnSpan="2">
    <Button Content="New" Command="{Binding Path=NewCommand}" />
    <Button Content="Save" Command="{Binding Path=SaveCommand}" />
    <Button Content="Delete" Command="{Binding Path=DeleteCommand}" />
</StackPanel>
 public ICommand DeleteCommand {
    get { return new RelayCommand(DeleteExecute, CanDeleteExecute); }
}

public ICommand SaveCommand {
    get { return new RelayCommand(SaveExecute, CanSaveExecute); }
}

public ICommand NewCommand {
    get { return new RelayCommand(NewExecute); }
}

Known Issues

There are numerous XAML applications around the world that use the MVVM pattern. This pattern is heavily promoted by the XAML platform community, Microsoft MVP's and respected technology leaders.

Expression Blend and the Visual Studio 2010 Designer both use the MVVM pattern.

The following links are from Martin Fowlers web site.