2011-06-07 28 views
27

这是自从我开始使用MVVM以来,我一直在努力的一个问题,首先在WPF中,现在在Silverlight中。MVVM和IOC:处理查看模型的类不变量

我使用IOC容器来管理Views和ViewModels的分辨率。视图往往是非常基本的,有一个默认的构造函数,但ViewModels倾向于访问真正的服务,所有这些都是构建所需的。再次,我使用IOC容器来解决问题,所以注入服务不是问题。

成为问题的是将所需数据通过IOC传递给ViewModel。作为一个简单的例子,考虑一个允许编辑客户的屏幕。除了可能需要的任何服务之外,此屏幕的ViewModel还需要客户对象来显示/编辑客户的数据。当做任何类型的(非MVVM)库开发时,我认为它是一个不可修改的规则,类不变量是通过构造函数传递的。如果我需要上下文相关的数据来建造课程时间所讨论的类是容器管理的,我倾向于使用抽象工厂*作为桥梁。在MVVM中,这看起来像是矫枉过正,因为大多数ViewModel都需要自己的工厂。 (1)初始化/加载方法,其中我传递数据,这违反了通过构造函数强制类不变量的规则,(2)通过容器传递数据,如下所示:参数覆盖(Unity),以及(3)通过全局状态包(ugh)传递数据。

将特定于上下文的数据从一个ViewModel传递到下一个的一些备选方法是什么?是否有任何MVVM框架解决这个特定的问题?

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

编辑:

我忘了补充:一些我列出的选项中甚至没有可能的,如果你正在做的“检视首个” MVVM,除非你先通过数据的视图,然后到视图模型。

+3

谢谢你提出这个问题。我偶然发现了如何将数据传递给ViewModel的困境。幸运的是,使用autofac的自动生成委托工厂,我只有不必一路去声明一个全接口声明的工厂,但它仍然是非常冗长。 – Ants 2011-06-15 06:49:01

回答

5

我曾经在这个问题上挣扎很多。据我所知,目前还没有其他可行的方法。你似乎已经自己深深地思考了这件事。 我只是想要两个添加在原因我 0.5美分为什么我经常选择的选项(1):

  1. init方法是简单的比任何其他的选择来实现(当然,温莎的类型化工厂也一样简单);
  2. 没有构造函数参数的设计弱点可以减轻,以后在VM生命周期中强制检查初始化参数
  3. 您要调用init方法的“地点”与您将调用构造函数的地方相同(或抽象工厂);
  4. 不同于抽象工厂,你可以分析出在特定接口的init()方法,以处理多个VM不同继承路径上(如果neeeded);
  5. 这是一个公平的妥协(在这种情况下至少):如果你真的无法忍受它,只是去工厂的解决方案,而无需关心(非常小的)的复杂性开销。
7

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

假设您有一个CustomerListViewModel,其中列出了每位客户的摘要。选择客户时,您想要显示CustomerDetailViewModel。这可以采用客户ID或ICustomer类型,此类型先前在CustomerListViewModel中填入客户详细信息(取决于您想要何时加载数据)。

我想你要问的是如果CustomerDetailViewModel也需要一系列服务作为你想通过容器解析的依赖(通常是依赖链)。

由于您先做视图模型,您需要从CustomerListViewModel实例化CustomerDetailViewModel,并且您希望通过容器来实现,以便适当地注入依赖关系。

因此,你提到,你通常会通过一个抽象工厂模式做到这一点,例如ICustomerDetailViewModelFactory这被作为对CustomerListViewModel服务过去了。

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

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

例如,Unity有parameter overrides,请参阅here获取Castle Windsor支持。温莎城堡也有typed factory facility,所以你不需要实施具体的工厂类型,只需要抽象。

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

2

我不太确定MVVM和IoC是否适合在构造函数中使用类不变量。根据我的经验,是的ViewModels作为ICommand.Execute的结果,它允许一个简单的两个阶段的过程中产生的:

var vm = Container.Resolve<CustomerViewModel>(); 
vm.Model = CustomerRepository.GetCustomerModel(id); 

在这个阶段,我的看法没有视图模型的知识,而只会发生当我注入ViewModel到任何容器绑定到视图。我也使用DataTemplates来渲染ViewModel,这意味着我不必直接实例化View来提供DataContext。

所以,要回答,我会使用(1),并打破“规则”。