2: 使用Prism初始化程序(纯汉语版)

本篇内容讲解了Prism应用程序启动和运行都发生了什么。一个Pris应用程序在程序启动期间需要注册和配置——这被叫做引导应用程序。Prism引导过程包括创建和配置一个模块目录,创建一个例如Unity的依赖注入容器,为组合式UI配置默认区域适配器,创建和初始化壳视图,还有初始化模块们。

什么是引导器?

    引导器是一个负责初始化Prism应用程序的类。通过使用引导器,你可以更多的控制Prism组件连接到你的应用程序。

    Prism包括一个默认抽象Bootstrapper 基类,可以使用任何容器。多数在引导器类中的方法都是虚方法。你可以在你自定义的引导器类中重写它们。

引导器执行过程的基本步骤

  Prism还提供了一些继承自Bootstrapper的类,拥有一些大多数应用都需要的默认实现。仅留给你实现的步骤是创建和初始化壳。

依赖注入

   Prism构建的程序由一个容器提供依赖注入。类库提供和Untiy或是MEF一同工作的程序集,当然 也允许使用其他依赖注入容器,引导器步骤中就有配置容器和主持类型到容器。

   Prism包括UnityBootstrapper 和MefBootstrapper 类,都实现了大多数必要的功能。初上上图的步骤,这俩引导器还添加了跟自己容器相关的一些步骤。

创建壳

   在传统的WPF程序里,启动URI是在App。xaml文件里,指向主窗口。

   Prism程序,其引导器的职责是创建壳或主窗口。壳依靠的服务,如区域管理器,要在壳展示之前注册。

关键决定

在你决定使用Prism之后,有一些决定需要你来考虑:

  • 考虑用MEF,Unity还是其他容器作为你的依赖注入容器。这将决定你要用何种bootstraper。
  • 你该考虑你想要的应用程序的服务。这些需要注册到容器里。
  • 决定是否使用内置日志服务,如果不用,你需要创建其他日志服务。
  • 决定怎样去发现模块,使用直接代码引用,在模块上标注代码特性,配置或使用XAML。

余下的文章会提供更多详细信息。

核心方案

    创建启动方案是构建Prism应用程序非常重要的一部分。此章节描述怎样创建一个引导器并定义它创建壳,配置依赖注入容器,注册程序级别服务,还有怎样加载和初始化模块。

为你的应用程序创建一个引导器

  如果你选择Unity或MEF其中一个作为你的依赖注入容器,创建一个引导器非常easy。创建一个新类继承自 MefBootstrapper 或UnityBootstrapper。然后,实现CreateShell 方法,你还可以重写InitializeShell 方法用于对壳有啥特别操作。

Implementing the CreateShell Method 实现CreateShell方法

   CreateShell 方法允许开发者指定一个顶级窗口。壳一般就是 MainWindow 或 MainPage. 实现此方法,返回一个壳实例。在Prism应用程序中,你可以创建壳项目,或者从容器中解析它,这根据你程序的需求。

  一个使用ServiceLocator 解析壳对象的示例,代码如下所示。

protected override DependencyObject CreateShell()
{
    return ServiceLocator.Current.GetInstance<Shell>();
}
注意
你将经常看到使用ServiceLocator解析类型的示例而不是用依赖注入容器。ServiceLocator 是通过调用容器实现的,所有这样可以写出容器无关的代码。你也可以直接引用容器替换掉ServiceLocator

 实现初始化壳方法

    创建壳之后,你可能需要允许一些初始化步骤,确保壳可以展示。对于WPF应用程序,你可以将创建的壳对象赋给程序主窗口,如下所示(来自WPf版模块化开始入门)

protected override void InitializeShell()
{
    Application.Current.MainWindow = Shell;
    Application.Current.MainWindow.Show();
}

    基类的InitializeShell 什么也没做,所有不调用基类实现也没关系。

创建和配置模块目录

   如果你正创建一个模块应用程序,你需要创建并配置一个模块目录。Prism使用一个具体的IModuleCatalog 实例追踪程序启用的模块。这些模块需要被下载和驻留。

   引导器提供一个可保护的ModuleCatalog 属性指向一个目录,也提供了一个virtualCreateModuleCatalog 虚方法。基类实现是返回一个新的ModuleCatalog ;然而,此方法可以重写成返回一个不同的IModuleCatalog 的方法。如下所示:(来自MEF版模块化快速入门示例)

protected override IModuleCatalog CreateModuleCatalog()
{
    // When using MEF, the existing Prism ModuleCatalog is still
    // the place to configure modules via configuration files.
    return new ConfigurationModuleCatalog()
}

   无论在UnityBootstrapper 还是 MefBootstrapper 中,Run方法调用CreateModuleCatalog 方法并利用返回值设置类中的ModuleCatalog 属性。如果你重写此方法,不需要调用基类实现,因为你是要替换容器提供的功能。更多信息,请看"模块化应用程序开发."

创建和配置容器

   容器扮演了一个Prism程序中关键的角色。程序需要容器来加载需求的依赖项和服务。在容器配置期间,一些核心的服务项被注册。除了核心服务,你还需要一些程序相关的服务应该被添加。

核心服务

下表列出了程序无关的核心服务

服务接口

描述

IModuleManager

检索并初始化程序模块。

IModuleCatalog

包含程序中模块的元数据,Prism提供了一些不同的目录。

IModuleInitializer

初始化模块。

IRegionManager

注册和检索区域,区域是指一种可视化的布局容器。

IEventAggregator

事件集合,以松耦合方式连接发布者和订阅者。

ILoggerFacade

一个包装日志的机制,你也可以选择使用自己的日志机制。股票操盘参考实现(Stock Trader RI)使用的是微软企业库日志模块,使用EnterpriseLibraryLoggerAdapter类,作为一个实现自定义日志的示例。通过引导器的run方法,将日志服务注册到容器里。使用CreateLogger 的返回值。支持的其他日志器将不会工作;需要重写CreateLogger 方法才行。

IServiceLocator

允许Prism库访问容器。如果你想定做或扩展类库,此接口或许有用。

应用程序特定服务

   下表列出的是股票操盘程序的应用程序特定服务,这可以作为一个理解你应用程序提供的服务类型的一个示例。

股票操盘程序示例

描述

IMarketFeedService

提供实时(模拟的) 的市场信息。PositionSummaryViewModel 更新它屏幕位置上的信息就是根据此服务。

IMarketHistoryService

提供历史市场数据,显示所选基金的市场趋势线。

IAccountPositionService

提供了在组合投资的一组基金。

IOrdersService

显示提交的买卖订单

INewsFeedService

提供一个选择基金的新项。

IWatchListService

当新的观察项被添加时的处理服务

   Bootstrapper 继承的两个类,UnityBootstrapper 和 MefBootstrapper. 创建和配置不同的容器涉及不同的实现方式但却相似的概念。

在UnityBootstrapper创建和配置容器

   UnityBootstrapper 类的CreateContainer 方法创建和返回一个UnityContainer实例。大多数情况下,你不需要改变此功能;然而,此方法是虚的,因此你可以改。

   容器创建之后,需要配置它,ConfigureContainer 默认实现注册了一些Prism核心服务,如下。

注意
模块基本的服务在它自己的Initialize 方法中。
// UnityBootstrapper.cs
protected virtual void ConfigureContainer()
{
    ...
    if (useDefaultConfiguration)
 {
    RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true);
    RegisterTypeIfMissing(typeof(IModuleInitializer), typeof(ModuleInitializer), true);
    RegisterTypeIfMissing(typeof(IModuleManager), typeof(ModuleManager), true);
    RegisterTypeIfMissing(typeof(RegionAdapterMappings), typeof(RegionAdapterMappings), true);
    RegisterTypeIfMissing(typeof(IRegionManager), typeof(RegionManager), true);
    RegisterTypeIfMissing(typeof(IEventAggregator), typeof(EventAggregator), true);
    RegisterTypeIfMissing(typeof(IRegionViewRegistry), typeof(RegionViewRegistry), true);
    RegisterTypeIfMissing(typeof(IRegionBehaviorFactory), typeof(RegionBehaviorFactory), true);
    RegisterTypeIfMissing(typeof(IRegionNavigationJournalEntry), typeof(RegionNavigationJournalEntry), false);
    RegisterTypeIfMissing(typeof(IRegionNavigationJournal), typeof(RegionNavigationJournal), false);
    RegisterTypeIfMissing(typeof(IRegionNavigationService), typeof(RegionNavigationService), false);
    RegisterTypeIfMissing(typeof(IRegionNavigationContentLoader), typeof(UnityRegionNavigationContentLoader), true);

  }
}

  引导器的RegisterTypeIfMissing 方法很检查一个服务是否被注册了——服务不会被注册两次。这允许你重写默认注册项。你可以关闭任何默认服务;为做到这一点,重写Bootstrapper.Run 方法并传递个false. 你也可以重写ConfigureContainer 方法并关闭你不需要的服务,例如事件聚合。

注意
如果你关闭默认注册,则你需要手动注册需要的服务。

    为了扩展ConfigureContainer默认行为。只需重写它。如下所示(来自使用Unity模块化快速入门),注册ModuleTracker 类型作为IModuleTracker的实现。注册callbackLogger 作为回调日志器的一个单例。

protected override void ConfigureContainer()
{
    base.ConfigureContainer();

    this.RegisterTypeIfMissing(typeof(IModuleTracker), typeof(ModuleTracker), true);
    this.Container.RegisterInstance<CallbackLogger>(this.callbackLogger);
}

创建和配置MefBootstrapper容器

    MefBootstrapper 类的CreateContainer 方法做了一些事情,第一件,它创建一个AssemblyCatalog 和一个CatalogExportProvider。CatalogExportProvider 允许MefExtensions 程序集去加载默认Prism类型注册,并允许你重写默认类型注册。CreateContainer 创建并返回一个使用CatalogExportProviderCompositionContainer 实例。更多情况下,你将不需要改变此功能;然而,方法时虚的,因此你也可以改。

   容器创建之后,它需要在你的程序中配置。ConfigureContainer实现一系列核心Prism服务的注册。如下代码所示。如果你重写此方法,仔细考虑你是否应该调用基类默认注册的核心Prism服务,或者在你自己的实现中提供这些服务。

protected virtual void ConfigureContainer()
{
    this.RegisterBootstrapperProvidedTypes();
}

protected virtual void RegisterBootstrapperProvidedTypes()
{
    this.Container.ComposeExportedValue<ILoggerFacade>(this.Logger);
    this.Container.ComposeExportedValue<IModuleCatalog>(this.ModuleCatalog);
    this.Container.ComposeExportedValue<IServiceLocator>(new MefServiceLocatorAdapter(this.Container));
    this.Container.ComposeExportedValue<AggregateCatalog>(this.AggregateCatalog);
}
注意
MefBootstrapper中,核心服务作为单例添加到容器中。

    除了提供CreateContainer 和ConfigureContainer 方法,MefBootstrapper 也提供两个方法来创建和配置AggregateCatalog 。CreateAggregateCatalog 方法创建并返回一个AggregateCatalog 对象。和MefBootstrapper中其他方法一样,此方法也是虚的,你可以重写它。

   ConfigureAggregateCatalog 方法允许你添加类型注册到 AggregateCatalog 。如下所示(来自MEF模块化快速入门中加载模块A和模块C):

protected override void ConfigureAggregateCatalog()
{
    base.ConfigureAggregateCatalog();
    // Add this assembly to export ModuleTracker
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(QuickStartBootstrapper).Assembly));
    // Module A is referenced in in the project and directly in code.
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(ModuleA.ModuleA).Assembly));
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(ModuleC.ModuleC).Assembly));

    // Module B and Module D are copied to a directory as part of a post-build step.
    // These modules are not referenced in the project and are discovered by inspecting a directory.
    // Both projects have a post-build step to copy themselves into that directory.
    DirectoryCatalog catalog = new DirectoryCatalog("DirectoryModules");
    this.AggregateCatalog.Catalogs.Add(catalog);
}

更多信息

  有关MEFAggregateCatalog, 和AssemblyCatalog,的更多信息,请看在MSDN上的 Managed Extensibility Framework Overview 。

原文地址:https://www.cnblogs.com/DoubleChen/p/3688305.html