October 2, 2014 · Best Practices Patterns WPF .NET

Understanding the MVVM Pattern

One of the recommended best practices in Windows Presentation Foundation (WPF) development is using the Model-View-ViewModel pattern. It is quite a bit different from the classic "code-behind" approach, and it can take a while to get fluent in thinking this way.

In the classic approach, the developer manually wires the UI together. Code is assigned to events and data is copied to/from UI elements and the state of the visual interface is managed directly.

Here's an illustrative code sample, handling a button click event:

    private void btnCreateGroup_Click(object sender, RoutedEventArgs e)
            btnCreateGroup.IsEnabled = false;
            if (!String.IsNullOrEmpty(txtGroupName.Text))
                txtUserMessage.Text = "Please enter a group name";

As you can see, the window instance has intimate knowledge of the view elements, including element names and types.

If a ComboBox is changed to a TextBox in the XAML view, it requires that all references to this element in the code-behind be updated and assignments checked and changed. This violates the "separation of concerns" principle, with View elements driving changes in the backend. Whatever happened to the idea of Views being just a presentation of data exposed by the window?

Another issue is that the code-behind cannot be tested apart from the XAML view. This is key: in the classic approach, testing requires a UI automation tool, since the "business logic" and the "presentation logic" are bound together intricately in the code-behind.

The MVVM approach addresses these issues, using the following core conceptual framework:

  1. The ViewModel represents the state and capabilities of the window and encapulates the business logic.

  2. The View is bound to the ViewModel. Specific UI elements are bound to specific ViewModel properties in the XAML via binding attributes, like so:
    <TextBox Text="{Binding Path=MyProperty, Mode=TwoWay}" />

  3. The ViewModel must remain ignorant of the View. It should not directly assign data to, or read data from UI elements. UI elements are never accessed by name in a ViewModel. One UI element may reference another by name, but between the View and the ViewModel, only data-binding is used (see #4).

  4. Data-binding is used to update the View and ViewModel, behind the scenes.

  5. Commands from the View are relayed to the ViewModel, causing it to perform operations. The results of operations are automatically propagated to the View through bound properties.

  6. Messages are passed from the ViewModel to the View using a Messaging interface (never directly) to keep things loosely coupled and testable. Depending on the application, screen-to-screen navigation may also need to be combined with Messaging.

All of this allows the ViewModel to be isolated from the View. In fact, it is possible to use a single ViewModel with both a WPF and a Silverlight View. A change in the View does not drive change in the ViewModel. And finally, the ViewModel, which encapsulates the business logic, can be tested independently from the View. The View then functions as it should -- as a visual representation, the presentation layer, over the ViewModel engine.

The magic that allows two-way data-binding and the relaying of commands is the secret sauce behind the MVVM pattern. Both WPF and Silverlight are setup to bind data via notification mechanisms that the ViewModel implements.

So, how is this done? One common approach to data-binding is by implementing an "INotifyPropertyChanged" interface. Similarly, commands (Button clicks etc) are relayed by implementing an "ICommand" interface. Often, the easiest way to implement these mechanisms is by using a toolkit library that is designed with MVVM applications in mind. Popular examples are Prism, MVVM Light toolkit and Caliburn Micro. Once these are in place, the benefits of MVVM can be leveraged to produce testable, easy to maintain and robust software.

For more information see Microsoft's article on MSDN: "Implementing The MVVM Pattern".

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket