47

有人遇到过使用 MVVM 在视图模型中关闭视图的巧妙方法吗?

也许有一种方法可以使用绑定来通知视图(窗口)关闭?

我非常感谢任何人的任何意见。

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

但我仍然显示 loginView - 所以我需要发出信号来卸载..

我也希望有一个通用的解决方案,因为我确信在其他情况下我需要做这种事情

有任何想法吗?

4

11 回答 11

36

编辑:有关更详细的说明,请参阅我的博客文章。

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

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

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

或者,就像肯特所说,您可以使用屏幕控制器在外部类中处理这种机制。

于 2009-09-28T11:04:53.320 回答
23

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

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

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

在视图模型中:

public void notifyWindowToClose()
{
    Messenger.Default.Send<NotificationMessage>(
        new NotificationMessage(this, "CloseWindowsBoundToMe")
    );
}

在视图中:

Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
    if (nm.Notification == "CloseWindowsBoundToMe")
    {
        if (nm.Sender == this.DataContext)
            this.Close();
    }
});
于 2010-07-20T19:36:55.447 回答
9

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

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

在视图的按钮 xaml 中:

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

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

if (parameter is System.Windows.Window)
{
    (parameter as System.Windows.Window).Close();
}
于 2014-02-27T03:37:47.310 回答
8

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

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

于 2009-09-27T20:19:52.620 回答
7

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>

于 2010-07-19T16:13:10.520 回答
4

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

于 2009-12-14T18:51:57.773 回答
2

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

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

于 2009-10-02T17:54:24.337 回答
2

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

ViewModel 应该如何关闭表单?

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

于 2010-08-06T17:03:12.607 回答
2

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

于 2012-06-30T18:37:52.240 回答
1

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

在您的视图模型中,您创建一个视图可以订阅的事件:

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

在您的视图中,您在 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();
        }

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

您甚至可以使用此方法从视图模型向视图发送消息。

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

于 2017-08-11T11:38:38.727 回答
0

要从 viewmodel 关闭视图,我使用了 Galasoft MVVM Light Toolkit,您可以在此处下载:http ://www.mvvmlight.net/

  1. 创建一个这样的类: public class ClosingRequested : MessageBase { }

  2. 将此添加到您的视图构造函数中: Messenger.Default.Register(this, vm, msg=> Close());

  3. 调用它来关闭你的窗口: Messenger.Default.Send(new ClosingRequested(), this);

于 2015-07-28T15:58:17.783 回答