使用ViewModelLocator
ViewModelLocator
用于以标准命名约定的方式将视图的DataContext
绑定到ViewModel的实例。
Prism的ViewModelLocator
有一个AutoWireViewModel
的附加属性,当设置为true
时,它会调用ViewModelLocationProvider
类中的AutoWireViewModelChanged
方法来解析View的ViewModel,然后将View的DataContext设置为该ViewModel的实例。默认情况下,此行为处于启用状态:如果你不想使用此行为,则需要选择关闭。
在使用WPF的情况下,这仅仅是使用区域导航和
IDialogService
时的默认行为。如果你正在使用视图注入,你的View需要自行选择启用该行为。
如下所示来使用AutoWireViewModel
附加属性。设置值为False
时表示选择关闭,True
时表示选择启用。
<Window x:Class="Demo.Views.MainWindow"
...
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="False">
为了定位一个ViewModel,ViewModelLocationProvider
首先尝试从所有由ViewModelLocationProvider
注册的映射中解析可能存在的ViewModel。(参照本章中的“自定义ViewModel注册”)。如果无法通过此方法解析到ViewModel,则ViewModelLocationProvider
回退到基于标准命名约定的方式以解析正确的ViewModel类型。
该约定假定:
- ViewModels和Views位于同一程序集中
- ViewModels在
.ViewModels
的子命名空间中 - Views在
.Views
的子命名空间中 - ViewModel的名称与View的名称相对应,并以“ViewModel”结尾
[!注意]
ViewModelLocationProvider
可以在Prism.Core NuGet包中的Prism.Mvvm
命名空间中找到。ViewModelLocator
可以在平台特定包(Prism.WPF、Prism.Forms)NuGet包中的Prism.Mvvm
命名空间中找到。
[!注意] 在使用Xamarin.Forms进行开发时,ViewModelLocator是必需的,并且会自动应用于每个View,因为它负责向ViewModel提供正确的
INavigationService
实例。因此在开发Xamarin.Forms应用程序时,ViewModelLocator
仅能设置为启用。
修改命名约定
如果你的应用程序不遵循ViewModelLocator
的默认命名约定,你可以更改约定以满足你的应用程序的需求。ViewModelLocationProvider
类提供了一个名为 SetDefaultViewTypeToViewModelTypeResolver
的静态方法,可用于提供将您自己的Views关联到ViewModels的命名约定。
如要更改ViewModelLocator
的命名约定,请重写App.xaml.cs
类中的ConfigureViewModelLocater
方法。然后在ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver
方法中提供自定义命名约定的逻辑代码。
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
var viewName = viewType.FullName.Replace(".ViewModels.", ".CustomNamespace.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
自定义ViewModel注册
在某些情况下,您的应用可能大多数遵循ViewModelLocator
默认的命名约定,但您也有一些ViewModel不遵循该约定。您可以通过使用ViewModelLocationProvider.Register
方法直接使用ViewModelLocator
来注册ViewModel到特定View的映射,而不是尝试自定义命名约定逻辑以有条件地满足您的所有命名要求。
以下示例展示了在名为MainWindow
的View和名为CustomViewModel
的 ViewModel之间创建映射的各种方法。
Type / Type
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(CustomViewModel));
Type / Factory
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve<CustomViewModel>());
Generic Factory
ViewModelLocationProvider.Register<MainWindow>(() => Container.Resolve<CustomViewModel>());
Generic Type
ViewModelLocationProvider.Register<MainWindow, CustomViewModel>();
[!注意] 直接使用
ViewModelLocator
注册你的ViewModels比依靠默认的命名约定更快。这是因为命名约定需要使用反射,而自定义映射直接将类型提供给ViewModelLocator
。
[!重要]
viewTypeName
参数必须是ViewModel的完全限定名称(Type.ToString()
),否则映射将失败。
控制ViewModels如何解析
默认情况下,ViewModelLocator
将使用您选择的DI容器来创建Prism应用程序以解析ViewModels。但是,如果您需要自定义ViewModels的解析方式或完全更改解析器,则可以使用ViewModelLocationProvider.SetDefaultViewModelFactory
方法来实现。
此示例显示了如何更改用于解析ViewModel实例的容器。
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewModelFactory(viewModelType) =>
{
return MyAwesomeNewContainer.Resolve(viewModelType);
});
}
这是一个示例,用来说明您可以如何检查为其创建的View和ViewModel的类型,以及如何执行您的逻辑来控制ViewModel的创建方式。
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewModelFactory((view, viewModelType) =>
{
switch (view)
{
case Window window:
//your logic
break;
case UserControl userControl:
//your logic
break;
}
return MyAwesomeNewContainer.Resolve(someNewType);
});
}