WPF (MVVM): Closing a view from Viewmodel?

2019-01-21 03:25发布

Anybody come across a clever way of closing a view in a viewmodel using MVVM?

Maybe there is a way of using binding to signal the view (window) to close?

I would really appreciate any input anyone has.

Basically i have a loginView that is bound to a loginViewModel, in the viewmodel (using binding on a command) i test to see if the login is successful and if it is i basically load up a new View (mainview) and attach its datacontext...

but i still have the loginView shown - so i need to signal it to unload..

I was also hoping for a generic solution because i am sure that i am going to need to do this sort of thing in other situations

Any ideas?

11条回答
迷人小祖宗
2楼-- · 2019-01-21 03:37

Not sure what MVVM framework you are using, but most contain some sort of messaging / notification solution that is easy have things register for messages which are sent. There is no reason that I can imagine that your view could not register for a message such as "CloseWindowsBoundTo" and the viewModel as the sender. Then in your view, you can just register for that message, and compare your current datacontext to the sender. If they match, close the window.

Simple, and keeps your view abstracted from your viewmodel.

Here would be my approach using MVVM-light toolkit:

In 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();
    }
});
查看更多
该账号已被封号
3楼-- · 2019-01-21 03:40

To close the view from viewmodel i used the Galasoft MVVM Light Toolkit which you can download here: http://www.mvvmlight.net/

  1. create a class like this: public class ClosingRequested : MessageBase { }

  2. add this to your view constructor: Messenger.Default.Register(this, vm, msg=> Close());

  3. call this to close your window: Messenger.Default.Send(new ClosingRequested(), this);

查看更多
Bombasti
4楼-- · 2019-01-21 03:44

I would use an ApplicationController which instantiates the LoginViewModel and shows the LoginView. When the user proceeds with the login screen the ApplicationController closes the LoginView and shows the MainView with its MainViewModel.

How this can be done is shown in the sample applications of the WPF Application Framework (WAF) project.

查看更多
走好不送
5楼-- · 2019-01-21 03:50

Generally you would use some kind of controller/presenter/service to drive the screen activation/deactivation. MVVM is not meant to be the One Pattern to Rule Them All. You will need to combine it with other patterns in any non-trivial application.

That said, in some situations in makes sense to have a view model that manages the life cycle of child view models. For example, you might have an EditorViewModel that manages a collection of child view models - one for each document being edited. In that case, simply adding/removing to/from this collection can result in the view activating/deactivating. But this does not sound like it fits your use case.

查看更多
【Aperson】
6楼-- · 2019-01-21 03:52

Just close in an EventHandler in code behind and handle everything else in the view model where you can use a command binding.

查看更多
Viruses.
7楼-- · 2019-01-21 03:55

You can also do this using event. Though you need like 3 lines of codes in your view code behind (some MVVM purist don't like this);

In your viewmodel, you create an event that the view can subscribe to:

    public event CloseEventHandler Closing;
    public delegate void CloseEventHandler();
    private void RaiseClose()
    {
        if (Closing != null)
            Closing();
    }

In your, view you subscribe to the event after your initializecomponent 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 you are ready to close the View from the ViewModel.

You can even use this method to send message to the view from the viewmodel.

The event can be put in an interface to avoid direct dependence of the view on the viewmodel.

查看更多
登录 后发表回答