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.
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:
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.
The practical approach to binding a View to its ViewModel should not require more than a one-liner:
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:
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.
Figure: Binding directly to the base class
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:
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?