Recently in a conversation with a friend, he described a problem with an algorithm he was writing for displaying a calendar with appointment data. His original algorithm worked fine, but when faced with appointment conflicts because of multi-booking, he had to employ a 2-pass algorithm over the data so that he could display the information properly in the calendar view. Let us explore this problem further (please also visit the references).
A well-structured architecture separates the presentation of information from the storage of information. The MVC model is the most commonly-used architectural framework with a view representing information display and the model representing the data source. The advantage of this approach is that you can have multiple views for the same data. For example, you can represent sales data in a tabular format, as a bar diagram, or expose it as XML data for consumption by other applications.
However, one model cannot adequately serve the needs of different views without additional overhead. For example, while a view that displays the data as a table can operate with just rows and columns of data, a bar chart view needs additional information (such as number of values and the data value range) to display the data properly.
Some of this is additional metadata about the information that the model could take responsibility for. However, it introduces a complication: For example, if metadata information is calculated as part of a GetAllRecords() operation, it introduces an overhead that simple views may not desire. A different scenario is when you have no control over changing the model. This may be the case where you are working with specialized storage and the vendor provides you an API. Without access to the source code, you cannot change the model interface.
Consider a view that must work with a rigid model. One strategy is to implement a 1-pass algorithm that calculates metadata and changes the view on the fly. Changing the view may be appropriate in some situations (a map that displays cities one by one), but not appropriate, or even practical, in others (a map that changes zoom sizes as it renders its data).
A 2-pass algorithm is better, because it gives you the capability to calculate metadata and then render the view appropriately. However, this re-introduces the original complexity of making the view responsible for handling data.
Hence, you introduce the ViewModel, a model that is meant for use by a specific view. The ViewModel is a bridge between the View and the DataModel (which was our original Model). The DataModel is responsible for data storage and isolates the rest of the application from the implementation details of data access and manipulation. The ViewModel provides a model that the specific view can use to render the presentation more easily.
Now, the performance issue: Clearly, there is some amount of data replication and duplicate data processing. But how much duplication is going on? Clearly, most views operate with a subset of the entire data. A calendar displays (usually) one person’s appointments over a small date range. A histogram is a summary of the data points, not the entire data set. However, if your View is processing a large volume of data and has performance issues, you may want to rethink many parts of the entire architecture itself, not just the Model.
Thus, the ViewModel converts the DataModel into a smaller data set that can be conveniently processed by the view. Since the ViewModel is associated with a specific View, its events, methods and properties can be changed to suit the demands of the View. All the time, the original Model remains intact to serve the common needs of all views.
- Model/View/ViewModel: http://chanson.livejournal.com/123094.html
- Introduction to Model/View/ViewModel pattern for building WPF apps: http://blogs.msdn.com/johngossman/archive/2005/10/08/478683.aspx
- WPF Patterns: http://www.orbifold.net/default/?p=550
- WPF Patterns: http://blogs.sqlxml.org/bryantlikes/archive/2006/09/27/WPF-Patterns.aspx
- DataModel-View-ViewModel: http://mathgeekcoder.blogspot.com/2007/12/datamodel-view-viewmodel.html