OrthoCoders

You can code it, I can help!

WPF MVVM Demystified

Motivation

Lately I have been hearing a few discussion about using MVVM as a pattern to work with desktop apps when using .NET and WPF. The first question usually is about justifying the use of the pattern compared to MVC or MVP. It's all about responsibilities and how the data and logic is organized. While I'm not going to describe all the differences I want to highlight some important aspects of the pattern when working with WPF applications. First Highlight: WPF is not WinForms. Why? NO CODE BEHIND! Second Highlight: What are the benefits of it? BINDING! Third Highlight: Is binding important when using WPF? ESSENTIAL! Fourth Highlight: What about generating the M - V - VM? NOT ENCOURAGED, BE CAREFUL!

The good old days with no binding

Before using WPF there was WinForms... The "idiomatic" way of making the views update in WinForms was either using code behind or letting the controller manipulate the view by knowing which view (or interface) was using, thus creating a dependency between them. The problem with that approach is that we are breaking encapsulation and assigning multiple responsibilities to classes that should be dedicated to only one of them. Remember, one source multiple views, and all that jazz. We should be able to create new views with no additional pain. I remember clearly wondering about :
"Wouldn't be great to have a way to bind my view to some kind of class so I don't have to keep having controllers that update the text field view when the text changes, etc?"
So I decided to create my collection of binders to make my life easier and look what happened next...

Binding as a first citizen

The next iteration of MS desktop tools brought WPF and the idiomatic way of building views was using Binding! Yay! Why is so good? Because the views use reflection to know when your source has changed! What's the tradeoff you ask? You need to implement a protocol to notify when change happens. Either using INotifyPropertyChanged interface or dependency properties. "Awesome!" - You say. "Now I can just grab my models and add the notification, and no more controllers, and..." - STOP! Wow, slow down..... take a deep breath, sit down... keep reading.

Modelling, abstraction and everything nice

We have clear responsibilities assigned between view and model. View is in charge of displaying what the Model represents. Now, because we want to use WPF we should not litter our classes with other responsibilities. Imagine tomorrow we have a different framework, what are we going to do? Change them again? And here is why the ViewModel makes so much sense. The class that matches with a ViewModel will provide all the necessary binding fields so they can be displayed in that view or any other view. Multiples views, same ViewModel. Is just binding after all.

No rule, to rule them all

Now, would that mean the we are going to have always an association one to one between Model, View and ViewModel? Even more, would that mean that all my "Models" are entities populated from an ORM? Not at all! There's no rule, just good design and modelling practices. A ViewModel may use multiple entities, or no entities at all! The fact that the name is Model does not imply necessarily that is a particular kind of class. Remember, is a pattern, so we identify the components of the pattern and named them accordingly. However patterns overlap, collaborate and some times use each other (sounds promiscuous, I know). So be careful! Code generation in my experience will bring you more sorrow than happy days! What classes are you going to generate anyways? How can you be sure before hand what all the models, etc, look like? Forcing all the objects to inherit base classes because they are all "ViewModels" or "Models" may produce the same result. There's no magic bullet or pill you can take. So what to do? Use binding, will save you lots of time, write some nice code (with tests to add confidence), and then when you have a very clear idea of what are you building and you can justify it, abstract, refactor and generate code or create base classes if needed.