Introduction
This article on MVVM architecture pattern allows the developer to distinguish between loosely coupled and tightly coupled applications.
Background
Before MVVM, some of the architecture patterns were tightly coupled in design. To overcome such a drawback, MVVM came into existence.
Using the Code
Problem Statement
What is Loosely Coupled System Design? How to achieve Low degree of coupling in WPF or Silverlight applications?
Solution
Loosely Coupled Application
Coupling is the dependency factor of one class on another that varies from low to high. In tightly coupled systems, changes in one class force the changes in another class and increase the efforts to make modifications. Tight coupling increases the maintenance cost and decreases reusability of component. So in order to achieve stable and low maintenance cost application, low degree of coupling is a desired trait of system design.
Loosely Coupled Application is to achieve separation of responsibilities and low coupling level. Architecture patterns are used to reduce coupling between objects, but architectural patterns help to improve system’s design.
The main advantage of loosely coupling is its changeability without breaking other modules in an unpredictable manner. The below diagram shows a sample approach how a designer and developer can work in an isolated manner to achieve loosely coupled system.
Figure 1: Designer’s and Developer's task segregation
Benefits of Loosely Coupled Applications
- Ease of Maintenance: Loosely coupled application is able to change the implementation in a certain subsystem, or service without affecting another subsystem or service. It allows UI designers and developers to work in a self-governing manner. It means that if in future View (look and feel) replaces with another View, it should not require ViewModel and Model to change.
- Ease of Testing: Loosely coupled application provides the ability for ease of testability using the many available unit testing frameworks (Nunit, etc.).
Challenges in Designing Loosely Coupled Applications
While designing complex UI applications, following are the four problems associated with UI:
- State: In Web Applications, session variables are used to maintain the state and in windows application it's simple UI level data. More efforts on state maintenance, the more it becomes complex.
- Logic: More logic to manipulate controls on User Interface, more complex it becomes.
- Synchronization: More the synchronization like coordination between UI controls and business objects, more complex becomes.
- Caching: Retrieving data from database for frequent access in application is the slowest way and a great hit on performance. So caching is the fundamental way of removing performance bottlenecks which results in slow data access. In case of single-tiered applications, different types of cache objects can be created at UI level (XAML, themes, images), business rules and Entity-Framework cache remain on the same page. Ideally, in case of N-tier applications, cache data should be placed as near as possible to the code that will use it. So the presentation layer will have caching UI of XAML, themes, images; business layer will have rapidly used workflows and business rules and data layer will have caching of frequently used Entity-Framework data objects.
The above mentioned problems are taken care in some architectural patterns such as MVC (Model-View-Controller), MVP (Model-View-Presenter) and MVVM (Model-View-ViewModel).
Following are the architectural patterns to provide a solution for the above mentioned problems.
MVC (Model-View-Controller)
The main objective of MVC pattern is to decouple the view from the actual data processing so that the same model can be used for several views. This is accomplished by using three different objects (Model
, View
and Controller
) that interact with each other in a loosely coupled manner. MVC pattern is used only for web (ASP.NET) forms.
- Controller: User interacts with the controller which in turn commands model and view to change. It’s responsible for Notice of Action.
- View: View is responsible for look and feel and isolated from the complex data processing. View can be XML/XSLT, Webpage or HTML.
- Model: Model responds to requests made by the controller and notifies views to update their look and feel. In short, Model is display-neutral.
Figure 2: MVC architecture
MVP (Model-View-Presenter)
A new approach was put forward by replacing Controller with Presenter and user requests are directed to View in spite of Presenter. Associated Presenter and View is having one-to-one mapping, i.e., the former is directly referenced with the View. Presenter updates the View (associated with) for the requested actions, which it performs on the Model. MVP pattern is used only for Windows Forms.
Figure 3: MVP architecture
Details on different tiers and their relationships:
Figure 4: 3-Layer Architecture along with MVC, MVP and MVVM
- Presentation Logic: The main concern of the Presentation Logic is to visualize information in a consistent and easy-to-understand way to the end-user. Design Patterns in action which includes functional implementation of UI platforms are mentioned below.
Design Patterns |
UI Platforms |
MVC |
ASP.NET Web Forms |
MVP |
Windows Forms |
MVVM |
WPF/Silverlight App |
- SOA to Business Logic: UI platforms MVC, MVP and MVVM consume services hosted under SOA. The Service Layer receives messages from the Presentation Logic and interprets the message, unpacks the Data Transfer Objects, and orchestrates and coordinates the interaction between Business Objects and Data Access Objects. Services Layer is the place where authorization, authentication, database transactions and data validation are implemented.
- Business Logic: Business Logic holds business objects that encapsulate business logic in the form of business rules. Business objects are unaware about the databases or data persistence.
- Business Logic to Data Logic: Business objects do not directly interact with the Data Logic; instead it’s handled by dedicated Data Access Objects to extract data from the business objects and to save into the database.
- Data Logic: Data Logic handles persistence of business objects. ADO.NET and LINQ-to-SQL are the two different technologies used under design patterns in action. ADO.NET includes .NET Framework data providers for connecting to a database, executing commands and retrieving results. When using LINQ-to-SQL, entities are mapped to Business objects.
Therefore, there is no direct interaction between Presentation Logic and Business Logic or Data Logic. Presentation interacts with the whole application via SOA (services) that manages security, data validation and transactions. Therefore, all communications with the application must go through single entry point hosted under services.
MVVM (Model-View-ViewModel)
The Model-View-ViewModel (MVVM) architecture pattern approach separates the business logic and presentation logic of the application, from user interface (UI). By maintaining a separation between the application logic and user interface (UI), it helps to address design and development issues which can result in making the application much easier to test and maintain. It can also greatly improve code reusability that allows UI designers and developers to more easily collaborate when developing their respective parts of the application.
MVVM design pattern, the UI of the application and the underlying presentation and business logic can be separated into three separate classes: the view, which encapsulates the UI and UI logic; the view model, which encapsulates presentation logic; and the model, which encapsulates the application's business logic and data.
MVVM pattern is used for WPF/Silverlight Applications.
MVVM Architecture Details
MVVM architectural pattern was introduced to provide segregation, event-driven programming approach and flexible testability of View, ViewModel and Model in WPF/Silverlight applications. MVVM is a special and close variant of MVP (Model View Presenter) design pattern since in MVVM, presenter is replaced by viewmodel. Model communicates with viewmodel with notifications and ViewModel communicates with the view with command binding and data binding.
Figure 5: Detailed MVVM Architecture
Class Responsibilities and Characteristics
The View Class
The View
class’s responsibility is to define the structure and lookup that user views on screen. It is a visual element, such as a page, user control, window, or data template. It uses the dominant data-binding capabilities of Silverlight/WPF to bind the properties defined in ViewModel to user controls that View is composed of.
User-events that are captured by the View are sent to the ViewModel through Commands. Now these commands execute methods defined in the ViewModel which contains logic. To update the View with updated data in viewmodel’s properties keeps the View bound to it.
As per MVVM compliant application, the View should contain minimum code, in an exceptional case code for a specific view. It contains UI controls and bindings of the properties defined in viewmodel to the controls which is again specific to the View. Code for validations specific to the View is also mentioned in the View. View has many-to-one relationship towards ViewModel. For reusability of code, User Control is used and data context of the ViewModel is set in view. Styles are also provided in the View only. In short, View is independent of viewmodel and vice-versa is also true.
The Model Class
Model
Class is responsible for data representation. It inherits INotifyPropertyChangedinterface
to notify ViewModel
if properties defined in Model
are modified. It is used to expose the data objects in an appropriate way that those can be easily managed and consumed by View
and ViewModel
. Objects like IDataErrorInfo
are inherited in Model
class to provide validations for the properties defined. RaisePropertyChanged
method is also added in Model
for every property onPropertyChangedEventHandler
.
The ViewModel Class
ViewModel
in the MVVM design pattern encapsulates the presentation logic and data for the view. It simply holds the data retrieved from data layer and View holds the formatted information, and ViewModel acts like a liaison in between the two. It is never tightly coupled with the View and notifies later, if any property changes in ViewModel. It might take inputs from View and place it on Model, or it might interact with a service to retrieve the model, then translate properties and place it on View. It also exposes methods, commands, and helps to maintain the state of the View, manipulates the Model as the result of actions on the View, and triggers events in View itself. ViewModel always updates Model and properties defined from View having UI level events mapped to commands in ViewModel by two-way data binding.
MVVM in Action
View
The below screen shot has covered UI level validations which are specific to View to show the look and feel of the validations raised in Model. TextBox
controls in the User Control are the target for these validations.
Figure 6: Setting Data Context to ViewModel
Figure 7: User Control Covering Validation on View level
Model
The below screen shot has covered server side validations specific to the properties defined in the Model. Values entered into the textboxes are validated through properties.
Figure 8: IDataErrorInfo and InotifyPropertyChanged in Model
Figure 9: Validation Implementation in Model class
ViewModel
The below screen shot has covered command objects such as: RelayCommand
inherited from ICommand
. RelayCommand
WPF introduced commanding, that allows binding the user event (button click event) with the execution logic. Every user defined command is derived from ICommand
. New ICommand
for each and every command may results in repetitive code. So RelayCommand
is a better way to have reusability. It’s a generic class that implements ICommand
to provide simple and small command declarations approach. ICommand
communicates that user has performed action on UI. ICommand
interface has three actions Execute
, CanExecute
, and CanExecuteChanged
. Execute
is the event handler routine for the control, CanExecute
is the method that determines if control is enabled of not and CanExecuteChanged
is an event that communicates the UI to check the UI whether the control should be enabled. Execution logic and can-execute logic, is introduced into its constructor.
Figure 10: Relay Command for command declaration
Figure 11: Command mapped in ViewModel
Unit Testing: View-ViewModel separation allows the view to be unit tested without the viewmodel. Since the viewmodel is responsible for the interactions with application, these unit test cases would cover the most important functionality while the view test cases will only have to contain testing of the look and feel features, e.g. data formatting, etc. Below is the screen shot of MVVM compliant application with unit testing project covering all the unit-test cases for methods defined in Model, View and ViewModel level.
Figure 12: MVVM Compliant Solution
Upsides of MVVM
Flexibility: Multiple views can be used with the same ViewModel
which allows completely different look and feel features of the same functionality depending on what different users’ requirement.
Re-Usability: Because of the segregation of UI and code level functionality, both the views and view\models have higher potential for re-use.
Low Degree of Coupling: Segregation of the user interface design and functionality development makes it possible to segregate developer’s work and designer’s work.
Testing: Unit testing is quite possible due to low degree of coupling, since UI testing will cover the testing of visual features, e.g., colors, font styles and functional test cases will cover classes in ViewModel
separately.
Downsides of MVVM
In spite of simple applications, MVVM architectural pattern is the perfect approach for complex applications since for the former it requires best coding practices and standards. Moreover for simple applications, there is no space for reusability, extensibility and scalability, i.e., MVVM says no to simple applications.
Rules for MVVM Compliant Applications
There are few rules to make applications MVVM compliant.
- Minimum Code Behind: View.xaml.cs and even event handlers are supposed to have no code. MVVM compliant application should have minimum code behind. In an exceptional case, code for a specific View can reside in code behind like where code is completely view-oriented and has nothing to do with model or viewmodel and other views. Dependency properties and any third party controls, not compliant with MVVM can be part of code behind.
- Events as Commands: All events generated by controls should be treated as commands.
- ViewModel as Data Context: As per MVVM compliant application neither viewmodel has instance of view nor view has the instance of viewmodel. As per the best practices, no need to type cast
ViewModel.DataContext
to viewmodel.
- Design ViewModel and View independently: In order to achieve MVVM compliancy, view and viewmodel should be designed independently to retain low level of coupling.
Best Practices in WPF/Silverlight Applications: PRISM
Prism provides the approach to design more easily and build flexible, rich and easy-to-maintain WPF desktop applications, Silverlight Rich Internet Applications, and Windows Phone applications.
Prism helps to design and develop composite WPF/Silverlight applications by taking important architectural principles such as separation of concerns and loose coupling into consideration so that loosely coupled components can evolve independently and can be easily and seamlessly integrated into the overall application. These types of applications are known as composite applications.
Figure 13 Composite Application Architecture with Prism Library
Components of Prism Application
The main components of a PRISM application are:
- Shell: The shell is a template that defines the structure of the application’s user interface.
- Regions: The shell contains different regions into which a view is injected into at runtime.
- Modules: A module is generally a single functional piece of the application. Modules generally should not have dependencies on other modules.
- Views: Modules contains different views, they are what defines the user interface for the application. MVVM is generally used to design views in PRISM.
- Bootstrapper: The
bootstrapper
is a class that is tasked with initializing the PRISM application. It allows developers to create and configure module catalogs, IOC containers, RegionAdapter
mapping and the application’s shell.
Conclusion
MVVM pattern is a guidance architecture pattern for designing and developing complex applications using WPF/Silverlight, to achieve better reusability, maintainability and extensibility with low degree of coupling. We should avoid using MVVM pattern for simple applications.