Close( ) – the MVVM chaos

Technorati Tags: ,,

pp_DSC1924 copy

I am an avid adopter of the Model-View-ViewModel pattern for designing applications. It is a sleek, very testable way to write software, but it has one major problem:

Because the ViewModel is unaware of its view, it follows that it is difficult to command a window to close itself.

I googled long and hard for solutions, but what I found was so complex and intricate that it would scare off any developer wanting to do some actual work.

What I give you here, is my own compromise between the want for simple, yet testable software vs the want to have a clean separation between a view and it’s viewmodel.

The BaseViewModel

Because every ViewModel implements INotifyPropertyChanged it is generally a good idea to write a base class that encapsulates this behaviour in most software projects.

In my opinion, every viewModel should also be able to request that a view should disappear for some reason.

Thus, my implementation of a baseclass for ViewModels looks like this:

image

By providing both an ICommand and a Method that both invoke the RequestCloseEvent, I can choose whether a View should close by binding to a button, or as a consequence of some logic in the viewmodel.

The CloseCommand property simply calls the RequestCloseEvent nothing more.

DataContext Binding

The practical approach to binding a View to its ViewModel should not require more than a one-liner:

image

The ( Application.Current as App ).ServiceLocator is my IoC Container; it has a public property for every ViewModel that I write. I add the container as a public property in app.xaml.cs. This way, it can be reached from all views.

The line above uses a simple extension method to do two things:

  • Register the ViewModel provided by the ServiceLocator as the DataContext for that view
  • Attach the RequestCloseEvent to the Views Close() method

Here’s the code:

image

The idea is that the event always closes the dialog.

You can then either bind a close button to the CloseCommand property of the BaseViewModel, or you can have your ViewModel fire the event through calling RequestClose( ) – or both.

 

image

Figure: Binding directly to the base class

 

 

image

Figure: Calling Close from a ViewModel method

So…how testable is this?

For all intents and purposes, I now have a loose enough coupling between my ViewModel and View to verify that the ViewModel is requesting a dialog to close:

image

Conclusion

The method I’ve given you gives a loose enough coupling to be testable, and keeps things simple. There is one single line of code to attach the View to it’s ViewModel, something I find to be an acceptable tradeoff from a pure separation.

The ViewModel also remains 100% compatible with the concept of test driven design, and is simple enough for teams of developers working on large software projects to use

PS: Who else does M.C.Escher inspired photography? 🙂

Leave a Reply