这一章节介绍Prism应用程序启动和运行时发生的内容。Prism应用程序在启动时需要有注册和配置的过程,这就是所谓的自自启动程序。
什么是自启动引导程序?
引导程序是一个类,它负责使用Prism库构建的应用程序的初始化。通过使用引导程序,你有更多的控制权使得Prism库组件如何连接到你的应用程序。
Prism库包括可被专门用于与任何容器使用一个默认的抽象的引导程序基类。许多在引导程序类的方法都是虚方法。您可以在自己的自定义引导程序中覆盖这些方法。
在自启动过程的基本阶段
Prism库提供了一些额外的基类,从引导程序而得,具有默认实现,适用于大多数应用。留下您的应用程序的引导程序来实现创建和初始化Shell的唯一阶段。
依赖注入
内置的Prism库的应用程序依赖于一个容器提供的依赖注入。该库提供了与Unity应用程序块(单位)或托管扩展性框架(MEF)的工作组件,它允许你使用其他的依赖注入容器。在引导过程的一部分是配置这个容器并注册类型的容器。
Prism库包括UnityBootstrapper和MefBootstrapper类,实现最必要的功能,无论是使用Unity或MEF在你的应用程序的依赖注入容器。除了在前面的图中所示的阶段中,每个引导程序添加特定于它的容器的一些步骤。
创建Shell
在传统的WPF应用程序中,App.xaml文件中使用启动统一资源标识符(URI)指定启动主窗口。在Silverlight应用程序,App.xaml文件后台代码中使用RootVisual属性来设置启动界面窗口。
在使用Prism类库创建的应用程序中,引导程序负责创建Shell或主窗口。这是因为Shell依赖于服务,例如该区域管理器,在Shell中显示之前需要注册。
关键决定
在你决定在你的应用程序中使用Prism后,这里还有一系列额外的决定需要你去做:
- 你需要去决定是否使用MEF,Unity或者其他的依赖注入容器,这将决定你将使用哪个引导程序类或者你需要自己为其他的依赖注入容器创建一个引导程序类
- 你需要考虑清楚应用程序的单独的服务,这需要在容器中被注册
- 决定是否使用内置的日志服务或者你需要自己创建另外的日志服务
- 决定模块是如何被应用程序查找并加载:代码方式明确声明,代码方式标记模块的属性,扫描路径,配置或者在XAML中
剩下的章节将会提供更多的细节
核心方案
搭建你的Prims应用程序用一个重要的部分就是创建一个启动队列,本节将讲述如何创建一个引导程序并自定义它去创建Shell,配置依赖注入容器,注册应用程序级服务,以及如何加载和初始化模块。
为你的应用程序创建引导程序
如何你选择了Unity或者MEF作为你的依赖注入容器,创建一个简单的引导程序将会非常简单,你需要创建一个继承于MefBootstrapper 或者UnityBootstrapper的类,然后,实现CreateShell方法,作为可选的,你可能会为了一个特殊初始化Shell重写InitializeShell方法。
实现CreateShell方法
CreateShell方法允许一个开发人员指定Prism应用程序的顶层窗口,这个Shell就是通常讲的 MainWindow 或 MainPage.通过返回应用程序的Shell类的实例来实现这个方法,在Prism应用程序中国,你可以创建Shell对象,或者从容器中解析,这依赖于你的应用程序的需求。
下面的代码实例中展示了使用ServieLocator来解析Shell对象
protected override DependencyObject CreateShell()
{
return ServiceLocator.Current.GetInstance<Shell>();
}
|
注意:你将会经常看到ServiceLocator被用作解析类型的实例而不是作为特殊的依赖注入容器,SericeLocator被调用者实现,所以它是一个很不错的选择使得容器与具体代码无关,当然,你也可以直接引用并使用容器来替代SericeLocator。
实现InitializeShell 方法
当你创建了一个Shell之后,你将会运行初始化步骤来确保这个Shell已经可以被显示,根据你创建的是一个WPF或者Silverlight应用程序,这个InitalShell方法将会不同。
在Sliverlight应用程序中,你将会看到Shell作为应用程序的visual root,如下所示:
protected override void InitializeShell()
{
Application.Current.RootVisual = Shell;
}
|
在WPF应用程序中,你将创建应用程序的Shell对象,并将它设置为应用程序的主窗口,如下所示(来自Modularity QuickStarts for WPF工程)
protected override void InitializeShell()
{
Application.Current.MainWindow = Shell;
Application.Current.MainWindow.Show();
}
|
在InitialzeShell方法的基类实现中不做任何事情,不去调用基类的实现将是安全的。
创建并配置模块目录
如果你实在搭建一个模块化的应用程序,你需要创建并配置一个模块目录,Prism使用了一个IModuleCatalog的具体实例来保存系统中可用的模块,哪些模块需要被下载,模块的位置的跟踪。
Bootstrapper提供了一个受保护的ModuleCatalog属性作为目录的引用同时也是虚方法CrateModuleCatalog的实现,在基类的实现中返回了一个新的ModuleCatalog;然而,这个方法可以被重写去提供一个不同的IModuleCatalog对象,例如下面来自Modularity with MEF for Silverlight QuickStart中的QuickStartBootstrapper工程中的代码
protected override IModuleCatalog CreateModuleCatalog()
{
// When using MEF, the existing Prism ModuleCatalog is still
// the place to configure modules via configuration files.
return ModuleCatalog.CreateFromXaml(new Uri(
"/ModularityWithMef.Silverlight;component/ModulesCatalog.xaml",
UriKind.Relative));
}
|
在UnityBootstrapper 和 MefBootstrapper类中,Run方法调用CreateModuleCatalog方法并且用方法返回值来设置类的ModuleCatalog属性,如果你重写了这个方法,调用基类的实现并不是必须的,因为你将会替换掉方法的功能,关于模块的更多的信息,请查看第四章的"Modular Application Development."
创建并配置容器
在使用Prism创建的应用程序中,容器扮演着一个关键的角色,无论是Prism类库和建立在它之上的应用程序依赖于容器中注入需要的依赖和服务。在容器配置的阶段,一些核心的服务被注册,除了这些核心服务,您可能必须提供额外的功能,因为它涉及到组成应用程序特定的服务。
核心服务
下面的表列出了Prism库中的核心的非特定应用的服务。
服务接口
|
描述
|
IModuleManager
|
定义检索并初始化应用程序模块的服务的接口。
|
IModuleCatalog
|
包含应用程序的模块中的元数据。Prism库提供了几个不同的目录。
|
IModuleInitializer
|
初始化模块
|
IRegionManager
|
注册和检索的区域,这是可视化的容器进行布局。
|
IEventAggregator
|
发布者和订阅者之间的松耦合事件的集合。
|
ILoggerFacade
|
一个日志机制的封装,所以你可以选择你自己的日志记录机制, 例如,你可以 通过EnterpriseLibraryLoggerAdapter类使用企业级类库Stock Trader Reference Implementation (Stock Trader RI)记录应用程序块。通过在引导程序中Run方法使用的CreateLogger 方法的返回值,日志服务被注册在容器内。 在引导程序中不去重写CreateLogger 方法而在在容器中注册另一个记录器将不起作用。
|
IServiceLocator
|
允许Prism类库访问容器,如果你想自定义或者扩展类库,它或许将很有用。
|
应用程序特定服务
下表列出了在 Stock Trader RI中使用的应用程序特定的服务。这可以被用来作为一个例子来理解服务应用程序可能会提供的类型。
Stock Trader RI中的服务
|
描述
|
IMarketFeedService
|
提供了实时的 (模拟) 市场数据. 当从服务中收到数据时PositionSummaryPresentationModel 将会更新屏幕上的点的位置
|
IMarketHistoryService
|
提供用于显示的趋势线所选基金历史市场数据。
|
IAccountPositionService
|
提供资金的投资组合名单。
|
IOrdersService
|
持续提交的买/卖订单。
|
INewsFeedService
|
提供选定基金的新闻条目。
|
IWatchListService
|
处理被添加到观察名单中的新条目
|
Prism提供了两种引导程序的派生类:UnityBootstrapper 和 MefBootstrapper,通过不同的实现方式创建和配置容器包含的那些类似的概念。
在UnityBootstrapper 中创建并配置容器
UnityBootstrapper 类中的CreateContainer方法只是简单的创建并返回了一个UnityContainer的实例,,在大多数情况下,您不需要更改此功能;然而,该方法是虚方法,从而具有灵活性。
在容器被创建之后,肯呢个需要为你的应用程序做些配置,在UnityBootstrapper中ConfigureContainer的实现中默认注册了一系列Prism核心的服务,如下所示:
注意:这是一个当某个模块在Initialze方法中注册模块级服务的例子。
C# 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 方法 决定了一个服务是否已经被注册,它不会被重复注册,这允许你可以通过配置来重写默认的注册信息,你也可以关闭默认注册任何服务;要做到这一点,使用重载Bootstrapper.Run方法并传入false。你也可以重写方法并且禁用你不想使用的服务,例如事件聚合器。
注意:如果你关闭的morning注册的服务,你需要手动的注册一些必须的服务。
为了扩展ConfigureContainer的默认行为,只需添加一个覆盖你的应用程序的引导程序的实现并且可选调用基类的实现,就像下面来自Modularity for WPF (with Unity) QuickStart中QuickStartBootstrapper工程中的代码一样,在它的实现中调用了基类的实现,注册了IModuleTracker的实现ModuleTracker类型,并且使用Unity注册了CallbackLogger的单例callbackLogger。
C# |
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的实例,在大多数情况下,您不需要更改此功能;然而,该方法是虚方法,从而具有灵活性。
注意:在Silverlight中,由于安全限制,不能使用类型信息来检索程序集,作为替代,Prism使用另外的方法,就是使用Assembly.GetCalllingAssembly方法来实现。
在容器被创建之后,肯呢个需要为你的应用程序做些配置,在MefBootstrapper中ConfigureContainer的实现中默认注册了一系列Prism核心的服务,如下所示:如果重写此方法,慎重考虑是否应该调用基类的实现注册Prism核心服务,或者您会在您的实现提供这些服务。
C# |
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中,Prism的核心服务是以单例的形式添加到容器中的,所以他们可以在整个应用程序中通过容器来定位。
此外,CreateContainer 和 ConfigureContainer 方法中,MefBootstrapper也提供了两个方法来创建并且配置MEF使用的AggregateCatalog,CreateAggregateCatalog方法仅仅创建并返回了AggregateCatalog对象,就像MefBootstrapper中的其他方法一样,CreateAggregateCatalog是个虚方法,必要时可以重写。
ConfigureAggregateCatalog方法允许你向AggregateCatalog命令式的添加类型注册。例如,来自 the Modularity with MEF for Silverlight QuickStart的QuickStartBootstrapper明确地向AggregateCatalog添加了ModuleA和ModuleC,如下所示。
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));
// Module C is referenced in in the project and directly in code.
this.AggregateCatalog.Catalogs.Add(
new AssemblyCatalog(typeof(ModuleC.ModuleC).Assembly));
}
|
更多信息