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

时间:2009-09-27 19:17:01

标签: wpf mvvm wpftoolkit

任何人都会遇到一种使用MVVM在视图模型中关闭视图的聪明方法吗?

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

我真的很感激任何人的任何输入。

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

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

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

有什么想法吗?

11 个答案:

答案 0 :(得分:35)

编辑:有关更详细的说明,请参阅my blog post

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

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

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

或者,像Kent说的那样,你可以使用屏幕控制器在外部类中处理这种机制。

答案 1 :(得分:22)

不确定您使用的MVVM框架,但大多数都包含某种消息/通知解决方案,这些解决方案很容易为发送的消息注册。没有理由我可以想象你的视图无法注册诸如“CloseWindowsBoundTo”和viewModel作为发送者的消息。然后在您的视图中,您可以只注册该消息,并将当前的datacontext与发送者进行比较。如果匹配,请关闭窗口。

简单,并保持视图从视图模型中抽象出来。

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

在ViewModel中:

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

答案 2 :(得分:9)

我知道这是一个老问题,但我有一个很好的方法,所以我想我会分享给其他任何绊脚石的人。我曾经使用dialogcloser附加行为,但我发现下面的解决方案更容易使用它。为简单起见,下面的示例以窗口上的关闭按钮为例。

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

按钮xaml中的视图:

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

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

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

答案 3 :(得分:8)

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

也就是说,在某些情况下,有一个视图模型可以管理子视图模型的生命周期。例如,您可能有一个EditorViewModel来管理子视图模型的集合 - 每个模型对应一个正在编辑的文档。在这种情况下,只需在此集合中添加/删除可以导致视图激活/停用。但这听起来并不适合您的使用案例。

答案 4 :(得分: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>

答案 5 :(得分:4)

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

答案 6 :(得分:2)

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

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

答案 7 :(得分:2)

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

How should the ViewModel close the form?

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

答案 8 :(得分:2)

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

答案 9 :(得分:1)

您也可以使用活动来完成此操作。虽然你的视图代码中需要3行代码(一些MVVM纯粹主义者不喜欢这样);

在viewmodel中,您可以创建视图可以订阅的事件:

    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关闭View时,只需调用RaiseClose()。

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

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

答案 10 :(得分:0)

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