csharpshare.com
Show / Hide Table of Contents

使用ViewModelLocator

Gitee仓库 Prism-Documentation-CH 时间 2023-1-19

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);
    });
}
本文导航
返回顶部 ©2022-2023 csharpshare.com    冀ICP备2022026743号-1     公安备案图标 冀公网安备 13052902000206号     Icons by Icons8