ViewModelLocator MVVM Light中的ViewModels

将所有ViewModel存储在SimpleIoc中是否正确? 比如我有三页MainPage,Photos,Directories(因此三个ViewModels – > MainVM,PhotosVM,DirectoriesVM)。 我应该在每个页面中设置DataContext ViewModelLocator中的视图模型属性或将ViewModels作为MainVM中的属性嵌套,并将每个页面DataContext绑定到Main.PhotosVMProperty,Main.DirectoriesVMProperty等? 任何人都可以解释我的想法和IoC的目的?

首先,让我们看看ViewModelLocator做什么以及为什么使用它:

ViewModelLocator在我们的App.xaml页面被声明为一个对象,并且是一个应用程序单例。 运行时,我们将有一个,并且只有其中一个可用于应用程序。

ViewModelLocator是MVVM Light中所有ViewModel的源代码。 对于每个ViewModel,我们将在ViewModelLocator上拥有一个属性,使我们能够获得View的ViewModel。 这段代码如下所示:

public class ViewModelLocator { public MainPageViewModel MainPage { get { return new MainPageViewModel(); } } } 

这是我的一个App.xaml:

 <Application.Resources> <vm:ViewModelLocator x:Key="ViewModelLocator" /> </Application.Resources> 

这是View.xaml中的一部分

 DataContext="{Binding MainPage, Source={StaticResource ViewModelLocator}}" 

到现在为止还挺好。 要回答您的第一个问题,您是否必须在MVVM Light中使用Ioc? 不需要,因为您的视图模型将被ViewModelLocator完全构build和实例化给您的视图。

现在谈谈第二个问题:IoC的目的是什么?

IoC旨在允许您执行以下操作:

用Mvvm Light你可以这样做:

 public class ViewModelLocator { public ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); if (ViewModelBase.IsInDesignModeStatic) { SimpleIoc.Default.Register<IDataService, Design.DesignDataService>(); } else { SimpleIoc.Default.Register<IDataService, DataService>(); } SimpleIoc.Default.Register<MainViewModel>(); } public MainViewModel Main { get { return SimpleIoc.Default.GetInstance<MainViewModel>(); } } } public class MainViewModel { public ObservableCollection<Foo> Foos { get; set; } public MainViewModel(IDataService dataService) { _dataService=dataService; Foos=_dataService.GetFoos(); } } 

当我打电话时解决我的MainViewModel

 SimpleIoc.Default.GetInstance<MainViewModel>() 

内部发生的事情是SimpleIoc检查MainViewModel是否有任何依赖关系(在其构造函数中的参数)。 然后尝试通过查看已经注册的接口来解决这些参数。 它以recursion的方式做到这一点,所以如果DataService具有依赖关系,那么它将被实例化,并在实例化时传递给DataService构造器。

我为什么要做这一切工作?

  1. 让您的课程轻松进行unit testing
  2. 使你的代码接口驱动。 这意味着你正在引用接口而不是具体的类
  3. 让你的代码松散耦合。 这意味着有人可以改变接口的实现,并且使用该接口的类不需要重新编码。
  4. 以自动方式解决您的类依赖关系。
  5. 在MVVM Light中,你会发现它可以告诉它什么时候在devise模式( ViewModelBase.IsInDesignModeStatic )中运行,这意味着你可以创builddevise时服务来提供你的viewmodels数据,这样你的Visual Studio中的View就包含了实际的数据。

MVVM Light有很多不错的function,但在我看来,服务定位器在视图模型上创build了不需要的视图依赖。 理想情况下,我希望在库A中具有ViewModelLocator,在库B中具有视图模型,在库C中具有视图。然后,可以根据未来项目的需要混合匹配这些视图。 然而,在MVVM Light的devise中,就我所见,视图(库C)总是依赖于ViewModelLocator(这是可以的),但是因为ViewModelLocator(库A)总是依赖于视图模型(库B),那么视图将总是依赖于视图模型(这是不行的,因为视图现在必须包括它曾经用过的所有视图模型库)。

我相信棱镜通过使用string键以某种方式解决这个问题。 我错过了什么吗?

哎呀! 我想我只是回答了我自己的问题。 解决scheme是使库A(ServiceLocator)专用于特定的解决scheme(产品)。 然后它仅包含对该解决scheme的视图模型的引用。 然后视图依赖于这个ServiceLocator,而这又取决于该产品的所有视图模型。 最终的结果是视图仅依赖于将用于该产品的视图模型。 事实上,我们正在为每个解决scheme复制ServiceLocator,因为这个模块仅包含特定于解决scheme的代码,所以没有任何问题。 当然,ServiceLocator的组件(如SimpleIoc类)对于所有的解决scheme都是通用的,但是这些已经被分解成我们在ServiceLocator中调用的可重用类。

总结一下,我试图解决的问题是假设一个解决scheme有6个视图模型,其中四个密切相关,其中两个密切相关。 因此我们创build了两个程序集,每个程序集都包含密切相关的视图模型 假设我们devise的产品使用了一组视图模型,并且该解决scheme被devise为运行Windows 8.现在视图都是不同的,我们只想重新使用一个视图模型集合(assembly)。 所以我们只是创build一个新的ServiceLocator程序集,指向这个视图模型的集合,以及其他任何我们需要的东西。 我们新的Windows 8视图现在依赖于这个新的ServiceLocator组件,并且仅依赖于我们的新产品(解决scheme)中使用的视图模型。