本篇内容讲解了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 创建并返回一个使用CatalogExportProvider的CompositionContainer 实例。更多情况下,你将不需要改变此功能;然而,方法时虚的,因此你也可以改。
容器创建之后,它需要在你的程序中配置。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); }
更多信息
有关MEF, AggregateCatalog, 和AssemblyCatalog,的更多信息,请看在MSDN上的 Managed Extensibility Framework Overview 。