WPF (MVVM):从 Viewmodel 关闭视图?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1484233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:02:37  来源:igfitidea点击:

WPF (MVVM): Closing a view from Viewmodel?

wpfmvvmwpftoolkit

提问by mark smith

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

有人遇到过使用 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...

基本上,我有一个绑定到 loginViewModel 的 loginView,在视图模型中(使用命令上的绑定)我测试以查看登录是否成功,如果是,我基本上加载了一个新视图(主视图)并附加其数据上下文。 ..

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

但我仍然显示了 loginView - 所以我需要通知它卸载..

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?

有任何想法吗?

采纳答案by japf

Edit:See my blog postfor a more detailed explanation.

编辑:有关更详细的解释,请参阅我的博客文章

When I need to achieve that, I use a IRequestCloseViewModel interface that I created.

当我需要实现这一点时,我使用我创建的 IRequestCloseViewModel 接口。

This interface contains only one event: RequestClose. This event is raised by the ViewModel (which inherits from a ViewModelBase class AND implement IRequestCloseViewModel) when it wants to close its associated view.

这个接口只包含一个事件:RequestClose。当 ViewModel(它从 ViewModelBase 类继承并实现 IRequestCloseViewModel)想要关闭其关联视图时,会引发此事件。

In my app, all Window inherit from an abstract class ApplicationWindow. This abstract class is notified each time the DataContext changed and in the handler checks if the DataContext support the IRequestCloseViewModel. If this is the case, an event handler is set up to close the Window when the event is fired.

在我的应用程序中,所有 Window 都继承自一个抽象类 ApplicationWindow。每次 DataContext 更改时都会通知此抽象类,并在处理程序中检查 DataContext 是否支持 IRequestCloseViewModel。如果是这种情况,则会设置一个事件处理程序以在触发事件时关闭 Window。

Alternatively, like Kent said, you can use screen controller that handle this mecanism in an external class.

或者,如 Kent 所说,您可以使用在外部类中处理此机制的屏幕控制器。

回答by Ryan from Denver

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.

不确定您使用的是什么 MVVM 框架,但大多数都包含某种消息/通知解决方案,这些解决方案很容易让事物注册发送的消息。我没有理由可以想象您的视图无法注册诸如“CloseWindowsBoundTo”之类的消息和作为发件人的 viewModel。然后在您看来,您只需注册该消息,并将您当前的数据上下文与发件人进行比较。如果它们匹配,请关闭窗口。

Simple, and keeps your view abstracted from your viewmodel.

简单,并使您的视图从您的视图模型中抽象出来。

Here would be my approach using MVVM-light toolkit:

这是我使用 MVVM-light 工具包的方法:

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();
    }
});

回答by cjmurph

I used to use the dialogcloser attached behavior, but i find the below solution easier where I can use it. The sample below takes an example of a close button on the window for simplicity.

我曾经使用 dialogcloser 附加行为,但我发现下面的解决方案更容易使用它。为简单起见,下面的示例以窗口上的关闭按钮为例。

pass the window as the command parameter.

将窗口作为命令参数传递。

in the button xaml for the view:

在视图的按钮 xaml 中:

CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"

in the command execute method in the view model:

在视图模型的命令执行方法中:

if (parameter is System.Windows.Window)
{
    (parameter as System.Windows.Window).Close();
}

回答by Kent Boogaart

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.

通常,您会使用某种控制器/演示者/服务来驱动屏幕激活/停用。MVVM 并不意味着成为统治所有这些的一种模式。您需要将它与任何重要应用程序中的其他模式结合起来。

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 EditorViewModelthat 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.

也就是说,在某些情况下,拥有一个管理子视图模型生命周期的视图模型是有意义的。例如,您可能有一个EditorViewModel管理一组子视图模型的集合 - 每个正在编辑的文档都有一个。在这种情况下,简单地向/从该集合添加/删除可能会导致视图激活/停用。但这听起来不适合您的用例。

回答by Adam Mills

http://adammills.wordpress.com/2009/07/01/window-close-from-xaml/

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>

<Style.Triggers> <DataTrigger Binding="{Binding CloseSignal}" Value="true"> <Setter Property="Behaviours:WindowCloseBehaviour.Close" Value="true" /> </DataTrigger> </Style>

回答by Adam Mills

You can make a command that attaches to the window and when executed closes the window. Then you can bind that command to a property on your view model, and execute the command when you want to close the window.

您可以创建一个附加到窗口的命令,并在执行时关闭窗口。然后,您可以将该命令绑定到视图模型上的属性,并在要关闭窗口时执行该命令。

回答by Jorge Vargas

This answer shows another way to do this:

这个答案显示了另一种方法:

How should the ViewModel close the form?

ViewModel 应该如何关闭表单?

It uses an attached property to bind the DialogResult window property to a ViewModel property. When setting the value of DialogResult to true or false, the view is closed.

它使用附加属性将 DialogResult 窗口属性绑定到 ViewModel 属性。将 DialogResult 的值设置为 true 或 false 时,将关闭视图。

回答by Tarion

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

只需在后面的代码中关闭 EventHandler 并处理视图模型中的所有其他内容,您可以在其中使用命令绑定。

回答by jbe

I would use an ApplicationControllerwhich 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.

我会使用ApplicationController来实例化 LoginViewModel 并显示 LoginView。当用户继续登录屏幕时,ApplicationController 关闭 LoginView 并显示 MainView 及其 MainViewModel。

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

WPF 应用程序框架 (WAF)项目的示例应用程序中显示了如何做到这一点。

回答by falopsy

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);

您也可以使用事件来做到这一点。尽管您的视图代码后面需要 3 行代码(一些 MVVM 纯粹主义者不喜欢这样);

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:

在您的 initializecomponent 方法之后,查看您订阅的事件,如下所示:

        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.

当您准备好从 ViewModel 关闭视图时,您只需调用 RaiseClose() 即可。

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.

事件可以放在一个接口中,以避免视图直接依赖于视图模型。