From MVC to MVVM in WPF — My Findings

The design for my exciting Multi-touch Music Catalogue is a typical MVC architecture. Or at least it was. Once I’d got to the end of the first iteration’s coding, I suddenly remembered reading in CODE magazine about the MVVM pattern. A bit of googling later and this is the de-facto architecture in WPF, Silverlight and WP7 — no question.

An opportunity had now presented itself for me to understand why it is the de-facto standard — and why it is better than MVC / MVP with which I am more familiar. Below are my findings specific to this project.Current Setup

Using MVC / MVP, the controller/view setup looks like this – with the view having to implement the IMusicView interface– in the process agreeing to provide behaviour to maintain state and control the UI — specific methods for transitioning between display modes.

Controller Interface

public interface IMusicController

{

IMusicView View { get; set; }

IEnumerable GetTags();

void SetSongMode();

void SongSearch(string tag, int limit = 10, int page = 1);

void SetSongDetailsMode(int songId);

Stream GetImage(string url);

}

View Interface

public interface IMusicView

{

ViewMode Mode { get; set; }

IMusicController Controller { get; set; }

IEnumerable Tags { get; set; }

IEnumerable Songs { get; set; }

Song Song { get; set; }

string StatusMessage { get; set; }

void SetSongMode();

void SetSongDetailsMode();

Stream GetImage(Release release);

}Combining View/Controller logic into a ViewModel

If I was working top-down (my usual preference) the view would tell me what properties my model needs. But this view is quite simple, so I can work from controller and view interfaces to create the view model and I won’t be too far away from where I need to be.

Step 1 — Straight-copy of data from view interface

Properties on the current view interface are the data items the view needs. So they are a straight swap to the view model (excluding the controller). The mode property is an interesting one because the view doesn’t need it. But I’ll take it anyway (and reconsider later).

View model created with presentation data

public class MusicCatalogueViewModel

{

public ViewMode Mode { get; set; }

public IEnumerable Tags { get; set; }

public IEnumerable Songs { get; set; }

public Song Song { get; set; }

public string StatusMessage { get; set; }

}

Step 2 — Translating view methods

Methods of the view interface correspond to commands in WPF. So at this point, I’ll create the commands and add them to the VM. Notice here that logic previously needed to be implemented by every view, is now relocated to the view model, as commands, and implemented for any view that uses the model.

I’ve had to remove the GetImage method because it doesn’t fit with MVVM. So I’ve relocated it to the song class. At this stage the un-implemented commands are also not a concern.

View model updated with presentation behaviour

public class MusicCatalogueViewModel

{

public ViewMode Mode { get; set; }

public IEnumerable Tags { get; set; }

public IEnumerable Songs { get; set; }

public Song Song { get; set; }

public string StatusMessage { get; set; }

public ICommand SetSongMode

{

get { return new SetSongModeCommand(this); }

}

public ICommand SetSongDetailsMode

{

get { return new SetSongDetailsModelCommand(this); }

}

}

Step 3 — Translating controller methods

Behaviour currently on the controller (arguably presenter) now also belongs in the VM too

View model updated with controller behaviour

public class MusicCatalogueViewModel

{

public ViewMode Mode { get; set; }

public IEnumerable Tags { get; set; }

public IEnumerable Songs { get; set; }

public Song Song { get; set; }

public string StatusMessage { get; set; }

public ICommand SetSongMode

{

get { return new SetSongModeCommand(this); }

}

public ICommand SetSongDetailsMode

{

get { return new SetSongDetailsModelCommand(this); }

}

public ICommand SongSearch

{

get { return new SongSearchCommand(this); }

}

}

One new addition, SongSearch, is the only code needed from the controller; mainly because the methods on the view delegated responsibility to a similar method on the controller. Logic previously in the controller will now be relocated to the appropriated commands (ICommand).Implementing INotifyPropertyChanged

In a nutshell, to keep view elements and the data they bind to synchronised, a VM must announce when one of its properties has changed. It does this by implementing INotifyPropertyChanged and specifying when an update occurs.

View model after implementing INotifyPropertyChanged

public class MusicCatalogueViewModel : INotifyPropertyChanged

{

private Song _song;

private IEnumerable _tags;

private IEnumerable _songs;

private string _statusMessage;

public ViewMode Mode { get; set; }

public IEnumerable Tags

{

get { return _tags; }

set

{

_tags = value;

NotifyPropertyChanged(“Tags”);

}

}

public IEnumerable Songs

{

get { return _songs; }

set

{

_songs = value;

NotifyPropertyChanged(“Songs”);

}

}

public Song Song

{

get { return _song; }

set

{

_song = value;

NotifyPropertyChanged(“Song”);

}

}

public string StatusMessage

{

get { return _statusMessage; }

set

{

_statusMessage = value;

NotifyPropertyChanged(“StatusMessage”);

}

}

public ICommand SetSongMode

{

get { return new SetSongModeCommand(this); }

}

public ICommand SetSongDetailsMode

{

get { return new SetSongDetailsModelCommand(this); }

}

public ICommand SongSearch

{

get { return new SongSearchCommand(this); }

}

public event PropertyChangedEventHandler PropertyChanged;

public void NotifyPropertyChanged(string propertyName)

{

if (PropertyChanged != null)

{

PropertyChanged(this,

new PropertyChangedEventArgs(propertyName));

}

}

}Advantages of MVVM in this Example

Having made the switch from MVC to MVVM the first obvious benefit is lack of logic in the view — zilch to be precise. The further away from SmartUI the better.

In my tests and executable specifications, I can now do away with test doubles for the view. I black-box text my VM — as long as it works, all the view has to do is bind to the properties and commands (from a functional perspective).

Because the previously view and controller logic now sit in the VM, there is less overall code — no more view event handlers delegating calls to the controller. Less code is generally better, I think most would agree.

MVVM works in in WPF, Silverlight and WP7 in the same way. So if I make my application work on any of those platforms, I’ve got excellent reuse potential. Or If I create other applications — the foundational knowledge for developing them in an effective way.Drawbacks

Whereas MVC / MVP requires an interface and thus compile-time checking — MVVM has none of that — and for the same reason — view binds to properties via “magic strings” — there is no refactoring support.

Announcing a property has changed generally involves calling NotifyPropertyChanged in the setter — yes the setter — we now have backing fields for all view-bound properties. Small potatoes, though really.

What if I wanted to use this view model with another UI technology that doesn’t support data binding via INotifyPropertyChanged — well, you’d probably see something different — whereas MVC your new view just implements the interface and provides its own presentational behaviours. Off the top of my head, I can only imagine that’s WinForms — and not a concern for me.Conclusion

Switching from MVC to MVVM has been a relatively trivial task once I’d read a few blogs and watched a screencast or two. For my efforts I have an application that now works a way more suited to WPF. I also have a good understanding of how to design applications for not just WPF, but Silverlight and WP7 as well.

Now all my tests and executable specifications have broken. Better go and fix them so I can push my changes and allow you all to play with my code and tell me how there are millions of ways to do it better.