In my previous post, I created a small Windows Presentation Foundation (WPF) application demonstrating Storyboard Animations where I also described how and why to Model-View-ViewModel (MVVM) pattern to the code. Recapping, the benefits of adopting the MVVM pattern include providing a separation of concerns between the application logic and the presentation logic and should, in theory, result in improved testability, extensibility and maintainability. While researching information for that post I watched a few Pluralsight & YouTube videos, along with reading various blog posts as well as consulting MSDN. The one thing that struck me was the lack of information covering the negative aspects of adopting the MVVM pattern for development. Surely there must be some, right?
The main deficiency of MVVM, from my perspective, is that it isn’t supported out-of-the-box by WPF. In most cases, design patterns shouldn’t be imposed on us by framework/library providers: we should be free to adopt whatever design pattern we like. However, in order to support various features of MVVM we have two choices:
- Write the required boilerplate code ourselves
- Use a library/framework that has already done that for us
When I am looking for solutions to problems, perusing StackOverflow, I tend to favour solutions that are self-contained; I’m not a big fan of adding extra dependencies unless absolutely necessary. The main urge being the desire to keep things a simple as possible. Fewer dependencies results in fewer potential problems/compatibility issues. Conversely, writing boiler plate code is tedious and inefficient if a solution already exists.
Therefore I decided to evaluate the implementation of the MVVM pattern in the Storyboard Animations application using both Prism and MVVMLight. These are the two most popular frameworks used for implementing MVVM in WPF.
Replacing Dependency Properties
As mentioned in the previous post I had to replace all dependency properties from the View’s code-behind with standard properties in the ViewModel. The ViewModel also had to implement the INotifyPropertyChanged interface for broadcasting the PropertyChanged event each time the property was updated. I created a base class with this functionality for each ViewModel to derive from. Both Prism and MVVMLight also provide similar base classes ( BindableBase in Prism, ViewModelBase in MVVMLight) with a slight improvement using the CallerMemberNameAttribute for automatically identifying the name of the property being updated. On a side note, as of C# 6.0, this same functionality can be achieved using the nameof() expression.
Communication between ViewModels
Routed events are used for communicating between Views, but the same approach isn’t suitable for communication between ViewModels. Instead, I implemented a pseudo message bus with a Publish-Subscribe pattern using .Net events. While using .Net events can lead to potential memory leaks (i.e. subscribers being subscribed to events long after is necessary), that is not the case in my application, as their lifetimes match that of the application. The EventAggregator in Prism and Messenger in MVVMLight are proper implementations of a message bus that don’t suffer from this issue.
Subscribing to be notified of a scroll event:
1 |
mMessenger.Register<ScrollEvent>(this, ScrollHandler); |
1 |
mEventAggregator.GetEvent<ScrollEvent>().Subscribe(ScrollHandler); |
Publishing a finished scrolling event:
1 2 3 4 5 6 7 8 |
mFinishScrollingCommand = new RelayCommand(() => { mIsScrolling = false; ScrollLeft = false; ScrollRight = false; mMessenger.Send(new FinishScrollingEvent()); }); |
1 2 3 4 5 6 7 8 |
mFinishScrollingCommand = new DelegateCommand(() => { mIsScrolling = false; ScrollLeft = false; ScrollRight = false; mEventAggregator.GetEvent<FinishScrollingEvent>().Publish(null); }); |
Message Bus
A message bus is usually used for communicating between multiple applications, but it can also be used for communication between distinct components of a single application. Rather than each application/component being tightly coupled through individual connections to each other, they all refer to a single message bus for communication. Publishers send messages or events to the message bus, unaware of any subscribers that might be listening. Subscribers identify the messages or events that they are interested in through the message bus. MSDN offers a good description of a message bus including the pros and cons of its usage. Two of the main benefits of message buses include improved scalability and reduced application complexity. Applications/Components are only required to connect to a single source for communication meaning that adding new applications/components is straightforward.
Commands instead of Event Handlers
Moving logic from the code-behind files renders the in-built event handlers redundant for reacting to user input in the UI. In the previous post I described how Microsoft Blend supports the invocation of a command when an event is raised through Behaviours. Therefore, all the logic is moved from the event handlers to the commands defined in the ViewModels. Microsoft Blend is a design tool in Visual Studio for developing UI applications through WPF and Silverlight. Accessing the features of Blend requires you to add references to the relevant assemblies in your project (i.e. Microsoft.Expression.Interactions.dll and System.Windows.Interactivity.dll).
Source Code Proliferation!
Adopting the MVVM pattern leads to an increase in the number of source files in your project. Rather than just having a single XAML and code-behind file for each View, you now have an extra ViewModel file as well. You will also require various other source files to store the logic for communicating between the ViewModels, the logic for the commands and any other required services. Some of this will be hidden from you if you use Prism or MVVMLight. Also, Prism by default enforces a specific naming convention for Views and ViewModels. This can easily be disabled though using the ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver method.
In general, these extra files are excessive for small simple applications where scalability and maintainability are never likely to be issues.
Summary
Both Prism and MVVMLight provide a rich set of features for facilitating the implementation of the MVVM pattern. I haven’t listed all of the available features, only the main ones that I used in my application. While there are some minor costs involved, adopting MVVM along with either framework definitely aids the development of large UI applications with multiple distinct components.
Source Code
Both versions of the application can be found on Bitbuck here: MVVMLight, Prism