This project has moved and is read-only. For the latest updates, please go here.

This article has been moved to GitHub!



DataModel-View-ViewModel Pattern

Common abbreviations: DM-V-VM
Full name in a bottom-up order: Model-DataModel-ViewModel-View Pattern

Introduction

The DataModel-View-ViewModel design pattern is an extension of the Model-View-ViewModel design pattern. Please read the description of the Model-View-ViewModel design pattern first.

This design pattern introduces a new class, called DataModel. This class does not replace the Model. Instead it is responsible to wrap the Model in a GUI-friendly way. Here are some examples what the DataModel might do:
  • Provide Commands which are mapped to some functionality of the Model.
  • Manage application state which is related to the Model (e.g. Selection state).
  • Encapsulate properties of the Model and provide change notifications so that every View which uses this DataModel gets updated.

Definition

ViewModel: Represent the state and behavior of the presentation independently of the GUI controls used in the interface.

DataModel: Represent the state and behavior of Models in a GUI friendly way but independently of the GUI controls used in the interface.

Structure

The following UML class diagram shows the collaborating classes of this design pattern in a logical layered architecture.

DataModel-View-ViewModel Pattern
Figure 1: The structure of the DataModel-View-ViewModel Pattern

Participants

The types participating in this pattern are:
  • View contains the specific GUI controls and defines the appearance of the user interface.
  • IView declares the interface of the View. The ViewModel can communicate over this interface with the View. Related pattern: Separated Interface (PoEA).
  • ViewModel represents the state and behavior of the presentation.
  • DataModel represents the state and behavior of the model in a GUI-friendly way.
  • Model can be a business object from the domain layer or a service which provides the necessary data.
  • Controller is responsible for the workflow of the application. Furthermore, it mediates between the ViewModels. So it promotes loose coupling by keeping the ViewModels from referring to each other explicitly. Related patterns: Application Controller (PoEA), Mediator (GoF)
Remark
  1. The Controller is responsible to create the DataModel objects. This is shown via the composite aggregation in the UML diagram.
  2. A DataModel object can be shared by different ViewModels.
  3. The association showing that the View is allowed to access the Model directly is not drawn in the diagram. However, the View should restrict this access on simple data binding.

Collaborations

The following list contains only collaborations in which the DataModel is involved.
  • The View can call operations on the DataModel directly. The DataModel needs to communicate through events when it has to notify the View.
  • The View can collaborate with the Model but it should restrict this on simple data binding. It’s recommended to handle more complex operations by the DataModel.
  • The upward communication from the Model to the View or to the DataModel can be done through events. Especially, the property changed events can be raised on the Model to trigger the WPF data binding implementation. Related pattern: Observer (GoF).
  • The Controller can call operations on the DataModel directly, whereas the backward communication from the DataModel to the Controller might be done through events. Related pattern: Observer (GoF).

Liabilities

This specific implementation of the DataModel pattern has the following liabilities:
  • The DataModel is dependent on a specific GUI framework. We use the commanding and the weak event concept of WPF.
  • The DataModel might listen to events (e.g. PropertyChanged events) of the Model. In such a scenario you have to keep the lifecycle of the DataModel and the Model in mind. When the Model lives longer as the DataModel it is essential to unwire the event or to use weak events so that the garbage collector is able to remove the DataModel instance. The WPF Application Framework (WAF) supports weak events with the DataModel base class.

ViewModel vs. DataModel

The WPF Application Framework (WAF) supports the ViewModel and the DataModel pattern. The question might occur when to use which pattern:
  • The ViewModel is commonly used together with a WPF UserControl or a WPF Window on the View side.
  • The DataModel is commonly used together with a WPF DataTemplate on the View side.
  • The ViewModel has a direct relationship with the View.
  • The DataModel has a direct relationship with the Model.

Usage

The WPF Application Framework (WAF) provides some types which helps you to implement this pattern.

DataModel class

Derive your DataModel implementation from this class. The DataModel class provides an implementation for the INotifyPropertyChanged interface and it comes with a default implementation of a weak event listener.

DelegateCommand class

This class provides a simple implementation for the ICommand interface. The constructor requires a delegate which is called when the command is executed. A second delegate can be passed to the constructor which is called when the command needs to refresh its state. With the second delegate it is possible to enable or disable the command. The command state refresh is triggered through the RaiseCanExecuteChanged method.

This command implementation is an ideal candidate for the DataModel. By using the DelegateCommand, the DataModel gets informed when it should handle a user interface action (e.g. Button was clicked). You need to expose the commands in the DataModel through properties and bind on them in the View.

ConverterCollection class

If you need to synchronize a Model collection with an associated DataModel collection then you might find the ConverterCollection useful. It listens to the CollectionChanged event of the Model collection and synchronizes the DataModel collection.

The constructor of the ConverterCollection expects the Model collection and a converter delegate which is called when a new DataModel instance needs to be created for a new Model object.

Reference

Last edited May 14, 2016 at 8:15 PM by jbe2277, version 10

Comments

jbe2277 Feb 17, 2011 at 6:19 PM 
Please use Discussions or Issue Tracker for Feedback.