【发布时间】:2017-06-11 12:05:08
【问题描述】:
我有一个简单的 MVVM 应用程序。一些 ViewModel 执行异步处理,这需要通知 View 状态更新和处理完成的时间。
由于在 MVVM 中对 View 的直接调用受到限制,因此我选择了 Commands。不幸的是,即使任务已同步到主 (UI) 线程,从延续任务调用时命令也不会执行:
public void DoAction()
{
//NOTE: command gets executed correctly
AppCommands.SomeCommand.Execute(null, null);
// run some task asynchronously
Task task = new Task( ... );
task.ContinueWith(
taskAntecedent =>
{
//NOTE: command does not get executed at all!
AppCommands.SomeCommand.Execute(null, null);
},
TaskScheduler.FromCurrentSynchronizationContext());
task.Start();
}
如果 Execute 方法包含正确的目标元素(以便 WPF 可以遍历可视化树并找到命令绑定),则始终执行 coomand。 但这不能在 ViewModel 中完成,因为它不应该看到 View。
我尝试使用的其他一些解决方案:
依赖注入 - 通过构造函数将 View 作为接口注入到 ViewModel。可行,但这为错误创造了空间: 1. ViewModel 不能在 XAML 中使用,因为 ViewModel 不再有一个空的构造函数。 2. 即使我定义了一个空的constructor,开发者也可能忘记使用正确的constructor,并在其中注入正确的View(有些View有几个可能的ViewModel,可以被用户替换)。
路由事件 - ViewModel 应该是可替换的,这意味着 View 必须从旧模型中取消挂钩事件并重新挂钩到需要在 View 中进行代码隐藏的新模型(不是类似 MVVM)
服务 - 一些视图是用户控件,与 Windows 不同,它们没有 Loaded、Unloaded 事件 - 因此没有注册和注销服务的好地方。还可以创建多个控件,从而多次注册同一个服务,那么Views和ViewModels之间的绑定就不会是1:1了。
问题很简单:
如何从 UserControl 的 ViewModel 关闭窗口,无需在 View 端或用户/开发人员进行大量额外编码?
我想在 vanilla WPF 中执行此操作,而不是使用 3rd 方 MVVM 框架,因为应用程序应该是轻量级/易于理解的(尽可能少使用黑魔法)。
【问题讨论】: