另外征求一下大家的意见,发布这东西要不要像第一章那样分开发呢,其实我感觉这样合在一起特别长的不好看,分开的话可以很方便的定位自己想要的内容。不过如果分开的话想一起看又太蛋疼了,大家给点意见呗。
根据1楼的意见,从这章开始我将会配图,之前的图就不在补齐了。另外代码的空行就暂时没办法了。。我这没有其它编辑器,向大家不好意思下。。另外,格式的话由于我是直接WORD拷到Windows Live上的,似乎格式都会不见,不知道如何解决。。实在没研究过。
您可以在以下位置找到原文:
http://compositewpf.codeplex.com/releases/view/55580
本章旨在说明一个Prism应用程序是如何启动和运行的。Prism应用程序在启动过程中需要一定配置和注册内容,这个过程也是所谓的应用程序启动引导。
Bootstrapper是一个负责初始化Prism应用程序的类。使用Bootstrapper,你就可以控制Prism库中的组件是如何连接到你的应用程序中的。
Prism库包含一个可以被继承的Bootstrapper抽象类,它可以使用与任何窗口。该类的大部分方法都是虚方法。你可以根据自己的需要重写这些方法。
(启动过程,发图太烦了,打字说明了:创建LoggerFacade,创建并配置模块列表,创建并配置容器,配置区域适配器,配置默认区域行为,注册框架异常类型,创建Shell,初始化Shell,初始化各模块。)
Prism库提供一些由Boostrapper继承的类,这些类提供了大部分应用程序所适用的实现。只有初始化并创建Shell这一场景留给你自己实现。
Prism应用程序需要一个依赖注入容器。本库提供了工作在Unity(Unity Application Block)和MEF(Managed Extensibility Framework)两种框架下的容器,当然你也可以使用自己定义的窗口。启动引导中的一部分内容就有配置窗口和向容器注册类型。
Prism库包含UnityBootstrapper和MefBootstrapper类,这两个类实现了大部分使用Unity或MEF作为依赖注入框架时所必需的功能。不同启动精灵也可能会向上图所示的启动过程中添加不同的步骤。
在传统的WPF应用程序中,启动窗口的URI是在App.xaml文件中定义的。在Silverlight应用程序中,是由App.xaml代码中的RootVisual所指定的。
但在Prism应用程序中,Bootstrapper负责创建Shell或者启动窗口。那是因为Shell依赖于一些服务,比如区域管理器,这些都需要在Shell显示前配置。
在你决定在你的应用程序中使用Prism,那么就必须做以下决定:
l 决定使用Unity,MEF,或者其它自定义依赖注入框架。这决定了你将使用哪一种Bootstrapper又或者是自定义一个Bootstrapper。
l 考虑你的程序中使用的一些特有服务,因为他们需要在容器中注册。
l 决定使用何种日志服务,比如使用内置的日志服务,或者是自己创建一个。
l 决定模块的启动顺序:通过详细的代码描述,通过自动检测,配置文件,或者xaml中的属性。
本章接下来的内容将讲述以上几点。
创建启动顺序是你创建应用程序的重要场景。本节描述了如何创建一个Shell,并且配置依赖注入容器,注册应用程序级服务,和如何读取和初始化模块。
如果你选择了Unity或者MEF框架,那么创建一个简单的Bootstrapper是非常容易的。你只要创建一个继承于UnityBootstrapper或者MefBootstrapper的类,并且实现CreateShell方法。如果有特殊需要,那么再重写InitializeShell方法。
CreateShell方法是给开发者指定Prism应用程序的顶层窗口所使用的。Shell它通常指MainWindow或者MainPage。你需要返回一个Shell的实例以实现该方法。在Prism应用程序中,你可以根据需求决定是指定一个Shell或者由容器指定。
以下实例就是使用ServiceLocator类指定Shell对象。
protected override DependencyObject CreateShell()
{
return ServiceLocator.Current.GetInstance<Shell>();
}
【注意】:你可以经常看到在依赖注入容器中使用ServiceLocator实例化对象取代直接实例化。ServiceLocator是由具体的容器实现的,这是一个使容器与其它代码脱耦的好方法。当然你不使用ServiceLocator而是直接引用。
当你创建了一个Shell,就需要做一些显示前的必要步骤。根据你所使用的是WPF或者Silverlight,InitializeShell方法有多种实现方法。在Silverlight中,你需要向下面这样设定RootVisual。
protected override void InitializeShell()
{
Application.Current.RootVisual = Shell;
}
如果你使用的是WPF,那么就要创建一个Shell对象,并且将其赋到MainWindow上。
protected override void InitializeShell()
{
Application.Current.MainWindow = Shell;
Application.Current.MainWindow.Show();
}
基类的InitializeShell是空的,还是不调用为好。
如果你创建一个模块化的应用程序,那么你就需要创建和配置模块列表。Prism通过IModuleCatalog的实例来确定哪些模块对应用程序有用,哪些模块需要下载,并且放至到何处。
Bootstrapper提供了一个ModuleCatalog的保护属性来表示该列表,它在虚方法CreateModuleCatalog中被实现。在基类的实现中,它返回一个空的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方法调用了CreateModuleCatelog方法,并且使用返回值初始化ModuleCatelog属性。如果你重写该方法,那么就不需要调用基类实现,因为你的代码已经提供了那些功能。更多信息,参考第四章“模块化应用程序开发”。
容器是Prism应用程序中非常重要的角色。无论是Prism库本身还是应用程序都基于依赖注入而框架。在容器配置过程中,只有少数几个核心服务被注册。除了这些服务以外,你可以定义一些服务提供一些应用程序需要的其它功能。
服务接口 |
描述 |
IModuleManager |
定义了检索和初始化模块的服务接口。 |
IModuleCatalog |
包含了模块的元数据。Prism库提供了若干种列表。 |
IModuleInitializer |
初始化模块。 |
IRegionManager |
注册和检索区域,也就是布局中的可视部分。 |
IEventAggregator |
一系列描述发布者和订阅者耦合关系的事件的集合。 |
ILoggerFacade |
一个日志机制的封装, 也可以自定义一个日志系统。Stock Trader Reference Implementation (Stock Trader RI) 使用了Enterprise Library Logging Application Block, 通过EnterpriseLibraryLoggerAdapter 类, 演示了使用自定义日志系统的方法。日志服务,也就是CreateLogger的返回值,通过启动器的Run 方法与窗口一同注册。除了重载启动器的CreateLogger方法,通过其它方法注册的日志服务都是无效的。 |
IServiceLocator |
允许Prism库引用容器。如果你需要自定义或者扩展库,那么它将会非常有用。 |
以下的服务是在Stock Trader RI中使用的,以此为例说明一个程序中可能使用到的服务。
Stock Trader RI中的服务 |
描述 |
IMarketFeedService |
提供模拟的实时市场数据。PositionSummaryPresentationModel 在不需要该服务特别提醒下更新屏幕数据。 |
IMarketHistoryService |
提供了显示走势图所需要的历史数据。 |
IAccountPositionService |
提供文件夹中的资金列表。 |
IOrdersService |
保存已经提交的销售/购买订单。 |
INewsFeedService |
提供与选择项相关的新闻列表。 |
IWatchListService |
在一个新的监视项被添加时被提交。 |
UnityBootstrapper和MefBootstrapper是Prism库提供的两个Bootstrapper的子类。它们使用不同的方法实现创建和配置使用相似的内容。、
UnityBootstrapper中的CreateContainer方法仅是返回一个UnityContainer的实例。大多数情况下,你不需要修改这个方法;当然,这是一个虚方法以此来保证灵活性。
在创建容器之后,应该都要根据应用程序需要配置你的容器。UnityBootstraper中实现了ConfigureContainer以注册Prism库的数种核心服务,如下所示:
【注意】:这是一个当模块需要在Initialze方法中注册模块级服务的方法。
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参数。你也可以重写一个自己的ConfigureContainer方法来禁用一些你不想要的服务,比如事件聚合器。
【注意】:如果你不使用默认配置,那么就要手动注册所需要的服务。
如果需要扩展默认的ConfigureContainer方法,那么就只需要在你的代码中重写他,根据需要是决定是否调用基类的方法。以下代码是在Modularity for WPF (with Unity) QuickStart示例中的QuickStartBootstrapper。这个实现调用了基类的配置方法,并且向Unity注册了IModuleTracker的实现类ModuleTracker和一个CallbackLogger的单例callbackLogger。
protected override void ConfigureContainer()
{
base.ConfigureContainer();
this.RegisterTypeIfMissing(typeof(IModuleTracker), typeof(ModuleTracker), true);
this.Container.RegisterInstance<CallbackLogger>(this.callbackLogger);
}
MefBootstrapper类中的CreateContainer方法做以下事情:首先,它创建一个AssemblyCatelog和一个CatalogExportProvider。CatalogExportProvider允许MefExtesions程序提供一些Prism类的默认导出内容,你也可以根据需要重载它们。然后CreateContainer创建一个使用CatalogExportProvider导出数据的CompositionContainer实例。大多数情况下,你不需要修改这个方法;当然,这是一个虚方法以此来保证灵活性。
【注意】:在Silverlight中,因为一些安全约束,不允许通过类型检索程序集,Prism提供了使用Assembly.GetCallingAssembly方法的其它方法取而代之。
在创建容器之后,应该都要根据应用程序需要配置你的容器。MefBootstraper中实现了ConfigureContainer以注册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);
}
【注意】:在MefBootstraper中,核心服务都是以单独的实例的形式加入到容器,这样你可以在整个应用程序中方便的定位其在容器中的位置。
除了CreateContainer和ConfigureContainer方法外,MefBootstraper还提供了两个用来配置MEF框架中AggregateCatalog属性的方法。CreateAggregateCatalog方法返回了一个AggregateCatalog的对象。和其它的MefBootstrapper方法一样,AggregateCatalog也是一个可以被重写的虚方法。
ConfigureAggregateCatalog方法则可以让你在必要时向AggregateCatalog添加注册类型。例如Modularity with MEF for Silverlight QuickStart实例中的QuickStartBootstrapper明确的向AggregateCatalog中添加了ModuleA和ModuleC,如下所示。
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));
}