ViewModel允许关闭窗口吗?
ViewModel允许关闭窗口吗?
最近,我回答了一个关于如何绑定窗口关闭按钮的问题。请不要过多关注那个问题本身,因为那不是我困扰的事情。在那种特定情况下,我甚至不会使用我的解决方案。我肯定会使用@ChrisW的解决方案。
然后,@SpikeX的回答出现了,现在我感到困惑。但是我必须感谢他。我无法停止思考,因为直到现在我可能一直以错误的方式思考MVVM。
所以我开始进行研究:
关闭ViewModel中的窗口
MVVM的基本概念-ViewModel应该做什么?
等等...
如您所见,我并不是宇宙中唯一一个从ViewModel中关闭窗口的人。但我真的可以这样做吗?或者说我真的不应该在ViewModel中使用窗口吗?MVVM对此真的如此严格吗?我的解决方案真的违反了MVVM模式吗?
ViewModel是否允许关闭窗口?
MVVM模式中的ViewModel是否允许关闭窗口?这个问题的出现是因为在MVVM模式中,ViewModel通常不应该直接操作视图(View),包括关闭窗口。然而,在某些情况下,我们可能需要在ViewModel中关闭窗口,这就引发了这个问题。
为了解决这个问题,可以使用以下解决方法:
首先,在XAML中声明命名空间xmlns:hlp="clr-namespace:AC.Frontend.Helper"
,然后使用hlp:AttachedProperties.DialogResult="{Binding DialogResult}"
进行绑定。这样可以在ViewModel中设置DialogResult属性,并将其与窗口的DialogResult属性进行绑定。这样,当ViewModel中的DialogResult属性更改时,窗口的DialogResult属性也会相应更改。
下面是一个示例的ViewModel代码:
public class WindowVm : ViewModelBase // ViewModel基类实现INotifyPropertyChanged { private bool? _dialogResult; public bool? DialogResult { get { return _dialogResult; } set { _dialogResult = value; RaisePropertyChanged(() => DialogResult); } } //... 其他属性 }
通过使用上述方法,我们可以在ViewModel中关闭窗口,同时保持MVVM模式的完整性。这样做的缺点是,我们无法完全测试ViewModel和与关闭窗口相关的逻辑。不过,我们需要权衡利弊,确定是否值得实现这样的解决方法。
ViewModel是否允许关闭窗口?
在我看来,ViewModel应该与其使用的客户端技术完全隔离。
由于您在实际的Window
实例上调用close方法,因此需要引用一个特定于客户端的程序集(在这种情况下是WPF),这几乎使得重用该ViewModel变得不可能。
如果您想创建WPF、Silverlight、Windows Phone、Windows Store App等客户端,您将无法在所有这些客户端上使用相同的ViewModel,因为Windows Phone可能不知道WPF窗口是什么。
此外,如果在ViewModel中引用实际视图元素,单元测试ViewModel将变得更加繁琐。
因此,您可以通过某种视图适配器将其抽象化,而不是直接引用窗口。
如果ViewModel只知道这样一个接口:
public interface IView { void Show(); void Close(); }
...每个客户端都可以创建自己的实现,并将其注入ViewModel中,以便在任何给定的客户端上执行正确的操作。
关键是ViewModel对实际视图一无所知,一切都隐藏在接口的实现中。