WPF(MVVM):从 Viewmodel 关闭视图?
Posted
技术标签:
【中文标题】WPF(MVVM):从 Viewmodel 关闭视图?【英文标题】:WPF (MVVM): Closing a view from Viewmodel? 【发布时间】:2010-12-01 20:06:36 【问题描述】:有人遇到过使用 MVVM 在视图模型中关闭视图的巧妙方法吗?
也许有一种方法可以使用绑定来通知视图(窗口)关闭?
我非常感谢任何人的任何意见。
基本上,我有一个绑定到 loginViewModel 的 loginView,在视图模型中(使用命令绑定)我测试登录是否成功,如果是,我基本上加载一个新视图(主视图)并附加它的数据上下文...
但我仍然显示 loginView - 所以我需要发出信号以卸载..
我也希望有一个通用的解决方案,因为我确信在其他情况下我需要做这种事情
有什么想法吗?
【问题讨论】:
【参考方案1】:编辑:更详细的解释见my blog post。
当我需要实现这一点时,我会使用我创建的 IRequestCloseViewModel 接口。
这个接口只包含一个事件:RequestClose。当 ViewModel(继承自 ViewModelBase 类并实现 IRequestCloseViewModel)想要关闭其关联视图时,会引发此事件。
在我的应用程序中,所有 Window 都继承自一个抽象类 ApplicationWindow。每次 DataContext 更改时都会通知此抽象类,并在处理程序中检查 DataContext 是否支持 IRequestCloseViewModel。如果是这种情况,则会设置一个事件处理程序以在触发事件时关闭窗口。
或者,就像 Kent 所说,您可以使用屏幕控制器在外部类中处理这种机制。
【讨论】:
嗨Jalfp,这听起来真的很棒,你有我需要所有窗口继承的抽象类的例子吗? .. 如果您也有包含 Irquestcloseviewmodel 的示例,那就太好了 接下来几个小时我将在我的博客上发表一篇文章。上线后我会第一时间通知你的:-) 这里是:japf.fr/2009/09/how-to-close-a-view-from-a-viewmodel 希望对您有所帮助:)【参考方案2】:不确定您使用的是什么 MVVM 框架,但大多数都包含某种消息传递/通知解决方案,可以很容易地为发送的消息进行注册。没有理由我可以想象您的视图无法注册诸如“CloseWindowsBoundTo”之类的消息,并且 viewModel 作为发送者。然后在您看来,您只需注册该消息,并将您当前的数据上下文与发件人进行比较。如果匹配,请关闭窗口。
简单,并使您的视图从您的视图模型中抽象出来。
这是我使用 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();
);
【讨论】:
只是想知道,它是否会因为您将链接传递给应该被释放的对象而导致内存泄漏?..【参考方案3】:我曾经使用 dialogcloser 附加行为,但我发现下面的解决方案更容易使用。为简单起见,下面的示例以窗口上的关闭按钮为例。
将窗口作为命令参数传递。
在视图的按钮 xaml 中:
CommandParameter="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=Window"
在视图模型的命令执行方法中:
if (parameter is System.Windows.Window)
(parameter as System.Windows.Window).Close();
【讨论】:
如果您坚持实施正确的 MVVM,这是最佳实践 如果您正在实施“正确”的 MVVM,这实际上是一种糟糕的做法。 ViewModel 层不应引用 UI 控件。这个问题的正确解决方案在这个答案***.com/a/3329467/967885【参考方案4】:通常您会使用某种控制器/演示器/服务来驱动屏幕激活/停用。 MVVM 并不意味着是一种统治它们的模式。您需要在任何重要的应用程序中将它与其他模式结合起来。
也就是说,在某些情况下,拥有一个管理子视图模型生命周期的视图模型是有意义的。例如,您可能有一个 EditorViewModel
来管理一组子视图模型 - 每个正在编辑的文档都有一个。在这种情况下,简单地向该集合添加/删除该集合可能会导致视图激活/停用。但这听起来不适合您的用例。
【讨论】:
【参考方案5】: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>
【讨论】:
【参考方案6】:您可以创建一个附加到窗口的命令,并在执行时关闭窗口。然后,您可以将该命令绑定到视图模型上的属性,并在您想要关闭窗口时执行该命令。
【讨论】:
【参考方案7】:我会使用一个 ApplicationController 来实例化 LoginViewModel 并显示 LoginView。当用户继续登录屏幕时,ApplicationController 会关闭 LoginView 并显示 MainView 及其 MainViewModel。
WPF Application Framework (WAF) 项目的示例应用程序显示了如何做到这一点。
【讨论】:
【参考方案8】:这个答案显示了另一种方法:
How should the ViewModel close the form?
它使用附加属性将 DialogResult 窗口属性绑定到 ViewModel 属性。当设置 DialogResult 的值为 true 或 false 时,视图被关闭。
【讨论】:
【参考方案9】:只需在后面的代码中关闭 EventHandler 并处理视图模型中可以使用命令绑定的所有其他内容。
【讨论】:
我是否会因为这样做而被 ViewModel 形状的闪电击中,而不是编写自己的 IRequestCloseViewModel 接口?【参考方案10】:您也可以使用事件来执行此操作。尽管您在后面的视图代码中需要 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()。
您甚至可以使用此方法从视图模型向视图发送消息。
可以将事件放在接口中,以避免视图直接依赖于视图模型。
【讨论】:
【参考方案11】:要从 viewmodel 关闭视图,我使用了 Galasoft MVVM Light Toolkit,您可以在此处下载:http://www.mvvmlight.net/
像这样创建一个类: 公共类 ClosingRequested : MessageBase
将此添加到您的视图构造函数中: Messenger.Default.Register(this, vm, msg=> Close());
调用这个来关闭你的窗口: Messenger.Default.Send(new ClosingRequested(), this);
【讨论】:
以上是关于WPF(MVVM):从 Viewmodel 关闭视图?的主要内容,如果未能解决你的问题,请参考以下文章