MVVM和IOC:处理View Model的类不变量

Phi*_*ler 30 c# dependency-injection inversion-of-control mvvm

自从我开始使用MVVM以来,这是我一直在努力解决的问题,首先是在WPF中,现在是在Silverlight中.

我使用IOC容器来管理Views和ViewModels的分辨率.视图往往是非常基本的,使用默认构造函数,但ViewModels倾向于访问实际服务,所有这些都是构造它们所必需的.同样,我使用IOC容器进行解析,因此注入服务不是问题.

成为问题的是使用IOC将所需数据传递给ViewModel.举个简单的例子,考虑一个允许编辑客户的屏幕.除了可能需要的任何服务之外,此屏幕的ViewModel还需要一个客户对象来显示/编辑客户的数据.

在进行任何类型的(非MVVM)库开发时,我认为通过构造函数传递类不变量是一个不可弯曲的规则.如果我需要特定于上下文的数据用于类构造时间并且所讨论的类是容器管理的,我倾向于使用抽象工厂*作为桥梁.在MVVM中,这看起来有点矫枉过正,因为大多数ViewModels都需要自己的工厂.

我尝试/考虑的一些其他方法包括(1)初始化/加载方法,其中我传递数据,这违反了通过构造函数强制类不变量的规则,(2)通过容器传递数据作为参数覆盖(Unity) ),以及(3)通过全局状态包(ugh)传递数据.

有哪些替代方法可以将特定于上下文的数据从一个ViewModel传递到另一个ViewModel?任何MVVM框架都能解决这个特定问题吗?

*它可能有自己的问题,比如需要在调用Container.Resolve()之间进行选择,或者不要让ViewModel容器管理.温莎城堡有一个很好的解决方案,但AFAIK没有其他框架.

编辑:

我忘了添加:如果您正在执行"View First"MVVM,我列出的某些选项甚至是不可能的,除非您先将数据传递给View然后再传递给ViewModel.

dev*_*tal 7

我不太清楚问题是什么,所以我将使用一个简单而有人为的例子.

假设您有一个CustomerListViewModel列出每个客户的摘要.选择客户时,您希望显示一个CustomerDetailViewModel.这可以采用客户ID,也可以采用ICustomer先前在CustomerListViewModel客户详细信息中填充的类型(例如,取决于您何时要加载数据).

我想你要问的是,如果CustomerDetailViewModel还要将一系列服务作为依赖关系通过容器解析(通常用于依赖链),会发生什么.

当你首先进行视图模型时,你需要实例化CustomerDetailViewModelfrom CustomerListViewModel,并且你想通过容器这样做,以便适当地注入依赖项.

因此,正如您所提到的,您通常会通过抽象工厂模式执行此操作,例如ICustomerDetailViewModelFactory,它将作为服务传递给CustomerListViewModel.

这种工厂类型有一个ICustomerDetailViewModel GetCustomerDetailViewModel(ICustomer customer)方法.此工厂类型将需要对IoC容器的引用.

当解决ICustomerDetailViewModel您的GetCustomerDetailViewModel工厂方法,你可以指定你想,当你调用解决您的容器上使用的ICustomer构造函数的参数值.

例如,Unity有参数覆盖,请参阅此处获取Castle Windsor支持.Castle Windsor还有一个类型化的工厂设施,因此您不需要实施具体的工厂类型,只需要实现抽象.

所以我会选择2!我们使用Caliburn.Micro,它解决了很多MVVM问题,但我不知道任何解决这个问题的框架.


Mar*_*ola 5

我曾经在这个问题上苦苦挣扎.据我所知,没有其他可行的方法; 你似乎已经深深地思考了这件事.我只想两个附加我的2 0.5美分,原因为什么我经常选择的选项(1):

  1. init方法比任何其他选项更容易实现(好吧,Windsor的Typed Factory也很简单);
  2. 可以减轻没有contructor参数的设计弱点,以便在VM生命周期的后期执行初始化参数的检查
  3. 你调用init方法的"地方"与调用构造函数(或抽象工厂)的地方相同;
  4. 与抽象工厂不同,您可以在特定接口中分解init方法,以便在不同的继承路径上处理多个VM(如果需要);
  5. 这是一个公平的妥协(至少在这种情况下):如果你真的不能忍受它,那就去工厂解决方案而不关心(很少)复杂性开销.