了解 MVVM 中的分离
Understanding the separation in MVVM
我最近学习了很多关于 MVVM 的知识,但还没有完全掌握 - 我最大的问题是:
What qualifies and what doesn't qualify as total Model View ViewModel separation, and how to see that "border"?
我会尝试根据我现在正在进行的项目来讨论我的担忧。
1.案例
假设我们有一个带有大量按钮的 MainWindow,每个按钮都会打开一个 'specific' 新的 Window。
注意:对于 DI,我使用的是 IoC 容器(Castle Windsor)。
MainWindow 有自己的 ViewModel,还有自己的 Model。我们的 IoC 容器在应用程序启动时对其进行初始化。
我们还有一个 TypedFactory(或任何其他工厂),我们想要创建其他 MVVM 对象。
现在,重要的部分:当我们按下按钮时,我们想要打开一个新的 window。如果不是 MVVM,则可以(不应该)调用 ViewModel 本身的 window 创建,只需执行以下操作:
WindowX ourNewWindow = new WindowX();
ourNewWindow.Show();
但是,这是 MVVM,我们应该严格避免在 ViewModel 中引用我们的视图。因此,我们可以将创建过程委托给我们的工厂。
我们可以通过将工厂注入我们的 ViewModel 构造函数并告诉工厂为我们创建视图来做到这一点。
private IFactory _factory;
public ViewModel(IFactory factory)
{
_factory = factory;
}
public void OpenWindow()
{
var newWindow = _factory.Create<NewView>();
newWindow.Show();
}
不过,这对我来说并不合适(如果我错了请纠正我)因为我们仍然在 ViewModel 中引用我们的新视图。
因此,我们可以添加另一层间接寻址,如 WindowMnager。让 windowManager 将 IFactory 作为依赖项并将 window 创建和管理的所有过程委托给它。
但是,对我来说,它仍然感觉在 View 和 ViewModel 之间存在不应该存在的 link。还是我完全错了,错误地处理了这个案子?
因此,最后一题是:
When does that forementioned "link" between Vie and ViewModel disappear and at which point do we stop creating more and more indirection levels?
Still, that doesn't feel right to me (correct me if I'm wrong) since we are still referencing our new View inside a ViewModel.
不,视图模型实际上对windows一无所知。它只知道工厂 interface(或 "window service" 接口或您选择的任何名称)。实际上创建 windows 的是此接口的 实现 ,您可以轻松地将实现替换为另一个实现而不影响视图模型。
这就是依赖注入的美妙之处。这里重要的是视图模型仅依赖于接口,因此视图模型和视图之间没有 直接 耦合。例如,实现接口的 class 可以很容易地在视图特定 project/assembly 中定义,并且接口本身和视图模型可以在视图模型 project/assembly 中实现,并且无需单独进行单元测试实际创建的任何 windows。
我处理它的方式:
- 从 MainViewModel 发送消息
- 向该消息注册一个处理程序,它将处理 window 的打开。
这样,触发的实际过程就与操作分开了。
我最近学习了很多关于 MVVM 的知识,但还没有完全掌握 - 我最大的问题是:
What qualifies and what doesn't qualify as total Model View ViewModel separation, and how to see that "border"?
我会尝试根据我现在正在进行的项目来讨论我的担忧。
1.案例
假设我们有一个带有大量按钮的 MainWindow,每个按钮都会打开一个 'specific' 新的 Window。
注意:对于 DI,我使用的是 IoC 容器(Castle Windsor)。
MainWindow 有自己的 ViewModel,还有自己的 Model。我们的 IoC 容器在应用程序启动时对其进行初始化。
我们还有一个 TypedFactory(或任何其他工厂),我们想要创建其他 MVVM 对象。
现在,重要的部分:当我们按下按钮时,我们想要打开一个新的 window。如果不是 MVVM,则可以(不应该)调用 ViewModel 本身的 window 创建,只需执行以下操作:
WindowX ourNewWindow = new WindowX();
ourNewWindow.Show();
但是,这是 MVVM,我们应该严格避免在 ViewModel 中引用我们的视图。因此,我们可以将创建过程委托给我们的工厂。
我们可以通过将工厂注入我们的 ViewModel 构造函数并告诉工厂为我们创建视图来做到这一点。
private IFactory _factory;
public ViewModel(IFactory factory)
{
_factory = factory;
}
public void OpenWindow()
{
var newWindow = _factory.Create<NewView>();
newWindow.Show();
}
不过,这对我来说并不合适(如果我错了请纠正我)因为我们仍然在 ViewModel 中引用我们的新视图。
因此,我们可以添加另一层间接寻址,如 WindowMnager。让 windowManager 将 IFactory 作为依赖项并将 window 创建和管理的所有过程委托给它。
但是,对我来说,它仍然感觉在 View 和 ViewModel 之间存在不应该存在的 link。还是我完全错了,错误地处理了这个案子?
因此,最后一题是:
When does that forementioned "link" between Vie and ViewModel disappear and at which point do we stop creating more and more indirection levels?
Still, that doesn't feel right to me (correct me if I'm wrong) since we are still referencing our new View inside a ViewModel.
不,视图模型实际上对windows一无所知。它只知道工厂 interface(或 "window service" 接口或您选择的任何名称)。实际上创建 windows 的是此接口的 实现 ,您可以轻松地将实现替换为另一个实现而不影响视图模型。
这就是依赖注入的美妙之处。这里重要的是视图模型仅依赖于接口,因此视图模型和视图之间没有 直接 耦合。例如,实现接口的 class 可以很容易地在视图特定 project/assembly 中定义,并且接口本身和视图模型可以在视图模型 project/assembly 中实现,并且无需单独进行单元测试实际创建的任何 windows。
我处理它的方式:
- 从 MainViewModel 发送消息
- 向该消息注册一个处理程序,它将处理 window 的打开。
这样,触发的实际过程就与操作分开了。