[ACCEPTED]-WPF (MVVM): Closing a view from Viewmodel?-wpftoolkit
Edit: See my blog post for a more detailed explanation.
When 17 I need to achieve that, I use a IRequestCloseViewModel 16 interface that I created.
This interface 15 contains only one event: RequestClose. This 14 event is raised by the ViewModel (which 13 inherits from a ViewModelBase class AND 12 implement IRequestCloseViewModel) when it 11 wants to close its associated view.
In my 10 app, all Window inherit from an abstract 9 class ApplicationWindow. This abstract class 8 is notified each time the DataContext changed 7 and in the handler checks if the DataContext 6 support the IRequestCloseViewModel. If this 5 is the case, an event handler is set up 4 to close the Window when the event is fired.
Alternatively, like 3 Kent said, you can use screen controller 2 that handle this mecanism in an external 1 class.
Not sure what MVVM framework you are using, but 13 most contain some sort of messaging / notification 12 solution that is easy have things register 11 for messages which are sent. There is no 10 reason that I can imagine that your view 9 could not register for a message such as 8 "CloseWindowsBoundTo" and the viewModel 7 as the sender. Then in your view, you can 6 just register for that message, and compare 5 your current datacontext to the sender. If 4 they match, close the window.
Simple, and 3 keeps your view abstracted from your viewmodel.
Here 2 would be my approach using MVVM-light toolkit:
In 1 the ViewModel:
public void notifyWindowToClose()
{
Messenger.Default.Send<NotificationMessage>(
new NotificationMessage(this, "CloseWindowsBoundToMe")
);
}
And in the View:
Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
if (nm.Notification == "CloseWindowsBoundToMe")
{
if (nm.Sender == this.DataContext)
this.Close();
}
});
I used to use the dialogcloser attached 7 behavior, but i find the below solution 6 easier where I can use it. The sample below 5 takes an example of a close button on the 4 window for simplicity.
pass the window as 3 the command parameter.
in the button xaml 2 for the view:
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
in the command execute method 1 in the view model:
if (parameter is System.Windows.Window)
{
(parameter as System.Windows.Window).Close();
}
Generally you would use some kind of controller/presenter/service 13 to drive the screen activation/deactivation. MVVM 12 is not meant to be the One Pattern to Rule Them All. You will need to 11 combine it with other patterns in any non-trivial 10 application.
That said, in some situations 9 in makes sense to have a view model that 8 manages the life cycle of child view models. For 7 example, you might have an EditorViewModel
that manages 6 a collection of child view models - one 5 for each document being edited. In that 4 case, simply adding/removing to/from this 3 collection can result in the view activating/deactivating. But 2 this does not sound like it fits your use 1 case.
http://adammills.wordpress.com/2009/07/01/window-close-from-xaml/
<Style.Triggers>
<DataTrigger Binding="{Binding CloseSignal}" Value="true">
<Setter Property="Behaviours:WindowCloseBehaviour.Close" Value="true" />
</DataTrigger>
</Style>
0
You can make a command that attaches to 4 the window and when executed closes the 3 window. Then you can bind that command to 2 a property on your view model, and execute 1 the command when you want to close the window.
I would use an ApplicationController which instantiates the LoginViewModel 6 and shows the LoginView. When the user proceeds 5 with the login screen the ApplicationController 4 closes the LoginView and shows the MainView 3 with its MainViewModel.
How this can be done 2 is shown in the sample applications of the 1 WPF Application Framework (WAF) project.
This answer shows another way to do this:
How should the ViewModel close the form?
It 4 uses an attached property to bind the DialogResult 3 window property to a ViewModel property. When 2 setting the value of DialogResult to true 1 or false, the view is closed.
Just close in an EventHandler in code behind 2 and handle everything else in the view model 1 where you can use a command binding.
You can also do this using event. Though 11 you need like 3 lines of codes in your view 10 code behind (some MVVM purist don't like 9 this);
In your viewmodel, you create an event 8 that the view can subscribe to:
public event CloseEventHandler Closing;
public delegate void CloseEventHandler();
private void RaiseClose()
{
if (Closing != null)
Closing();
}
In your, view 7 you subscribe to the event after your initializecomponent 6 method as below:
public View
{
*//The event can be put in an interface to avoid direct dependence of the view on the viewmodel. So below becomes
//ICloseView model = (ICloseView)this.DataContext;*
ProgressWindowViewModel model = (ProgressWindowViewModel)this.DataContext;
model.Closing += Model_Closing;
}
private void Model_Closing()
{
this.Close();
}
You just simply call RaiseClose() when 5 you are ready to close the View from the 4 ViewModel.
You can even use this method to 3 send message to the view from the viewmodel.
The 2 event can be put in an interface to avoid 1 direct dependence of the view on the viewmodel.
To close the view from viewmodel i used 6 the Galasoft MVVM Light Toolkit which you 5 can download here: http://www.mvvmlight.net/
create a class like this: public 4 class ClosingRequested : MessageBase { }
add 3 this to your view constructor: Messenger.Default.Register(this, vm, msg=> Close());
call 2 this to close your window: Messenger.Default.Send(new 1 ClosingRequested(), this);
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.