首先,让我们看一下ViewModelLocator的作用以及为什么我们使用它:
ViewModelLocator在我们的App.xaml页面中声明为对象,并且是应用程序单例。当应用运行时,我们将拥有一个且仅有一个该对象可用。
在MVVM Light中,ViewModelLocator是所有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会将完全构建并实例化的视图模型提供给视图。
现在来到你的第二个问题: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 是否有任何依赖项(构造函数中的参数)。然后它尝试通过查看已经在其注册的接口来解决这些参数。它以递归方式执行此操作,因此如果 DataService 有一个依赖项,则在实例化时将被实例化并传递给 DataService 构造函数。
为什么要做所有这些工作呢?
- 使您的类易于单元测试
- 使您的代码面向接口编程。这意味着您引用接口而不是具体类。
- 使您的代码松散耦合。这意味着某人可以更改接口的实现,消费该接口的类不关心并且不需要重新编码。
- 以自动化方式解决类的依赖关系。
- 在 MVVM Light 中,您会看到它可以告诉它是否在设计模式下运行(
ViewModelBase.IsInDesignModeStatic
),这意味着您可以创建设计时服务来提供视图模型数据,以便您的 Visual Studio 中的 View 包含实际数据。