I am trying to close a window from its ViewModel. I am using the MVVM pattern. I have tired to get the window using;
Window parentWindow = Window.GetWindow(this);
But I cannot do this, how do I get the window of the ViewModel so I am able to close the window. I want to be able to do this in code.
Can you find the parent window in code?
There is a useful behavior for this task which doesn't break MVVM, a Behavior, introduced with Expression Blend 3, to allow the View to hook into commands defined completely within the ViewModel.
ViewModels
should not be referencing theView
in any way, including closing windows, in MVVM.Instead, communication between the
View
andViewModel
is typically done through some kind of Event or Messaging System, such as Microsoft Prism'sEventAggregator
, or MVVM Light'sMessenger
For example, the
View
should subscribe to listen for event messages of typeCloseWindow
, and when it receives one of those message it should close itself. Then theViewModel
simply has to broadcast aCloseWindow
message anytime it wants to tell theView
to close.There's a brief overview of event systems in MVVM, and some examples, on my blog post about Communication between ViewModels if you're interested
You can define an action in your ViewModel
then, in your window (for example in the DataContextChanged) you can set this action :
Well, all this is part of a bigger dependency injection pattern, but basic principle is here... Next, you juste need to call the action from the VM.
yes referencing view in viewmodel isn't best practice. WHY? because when you unit test your viewmodel it is require you to instantiate view, for small view will not difficult to do that, but for a complex view with complex tree of dependency? that wont be good.
for me, the easiest way to do communication with view is by passing
IInputElement
on viewmodel constructor. the bennefit ofIInputElement
is Routed Event backbone, it hasRaiseEvent
andAddHandler
method required for routed event. thus you can bubble/tunnel/direct event to any view or viewmodel on your application freely without any additional library.here is my the simplified code on viewmodel but remember this technique only work for view first approach
on your View simply
and the root view (Window) of your application simply
and because
IInputElement
is interface rather than class, you easily create a mock class for your unit testor you can use mock library like RhinoMocks
for further reading, you can learn more about how to use Routed Event
Let the ViewModel do this, if really in need.
The Models says for example, that there are no longer valid data
pass that information to the ViewModel
the ViewModel recognizes, that it can no longer display anything
and then closes the window.
An empty view is the normal way of expressing that there are no more data