Prism在运行程序前,需要的组件像其他大部分程序架构一样在初始化阶段完成。Prism将这个启动加载器命名为Bootstarpper。在Bootstarpper中,按顺序加载一系列组件,如,moduleCatalog,container,还有UI的 regionAdapter,shell和module等等。
Bootstrapper
在Prism中,自带有基于Unity和MEF两种DI容器的Bootstrapper,分别为UnityBootstrapper和MEFBootstrapper。此文所有介绍都基于UnityBootstrapper,当然我们也可以定义自己的启动器(开闭原则,在后面的文章中还有很多类似的设计原则和设计模式)。Bootstrapper大部分方法是虚拟方法,定义如下:
1 #region 程序集 Microsoft.Practices.Prism.Composition.dll, v5.0.0.0 2 // F:\RefrenceProject\compositewpf-ff6316df3dadd0d24083d51aa1dea922d07fb47e\V5\Quickstarts\Hello World\HelloWorld.Desktop\packages\Prism.Composition.5.0.0\lib\NET45\Microsoft.Practices.Prism.Composition.dll 3 #endregion 4 5 using Microsoft.Practices.Prism.Logging; 6 using Microsoft.Practices.Prism.Modularity; 7 using Microsoft.Practices.Prism.Regions; 8 using System; 9 using System.Windows; 10 11 namespace Microsoft.Practices.Prism 12 { 13 // 摘要: 14 // Base class that provides a basic bootstrapping sequence and hooks that specific 15 // implementations can override 16 // 17 // 备注: 18 // This class must be overridden to provide application specific configuration. 19 public abstract class Bootstrapper 20 { 21 protected Bootstrapper(); 22 23 // 摘要: 24 // Gets the Microsoft.Practices.Prism.Logging.ILoggerFacade for the application. 25 protected ILoggerFacade Logger { get; set; } 26 // 27 // 摘要: 28 // Gets the default Microsoft.Practices.Prism.Modularity.IModuleCatalog for 29 // the application. 30 protected IModuleCatalog ModuleCatalog { get; set; } 31 // 32 // 摘要: 33 // Gets the shell user interface 34 protected DependencyObject Shell { get; set; } 35 36 // 摘要: 37 // Configures the Microsoft.Practices.Prism.Regions.IRegionBehaviorFactory. 38 // This will be the list of default behaviors that will be added to a region. 39 protected virtual IRegionBehaviorFactory ConfigureDefaultRegionBehaviors(); 40 // 41 // 摘要: 42 // Configures the Microsoft.Practices.Prism.Modularity.IModuleCatalog used by 43 // Prism. 44 protected virtual void ConfigureModuleCatalog(); 45 // 46 // 摘要: 47 // Configures the default region adapter mappings to use in the application, 48 // in order to adapt UI controls defined in XAML to use a region and register 49 // it automatically. May be overwritten in a derived class to add specific 50 // mappings required by the application. 51 // 52 // 返回结果: 53 // The Microsoft.Practices.Prism.Regions.RegionAdapterMappings instance containing 54 // all the mappings. 55 protected virtual RegionAdapterMappings ConfigureRegionAdapterMappings(); 56 // 57 // 摘要: 58 // Configures the LocatorProvider for the Microsoft.Practices.ServiceLocation.ServiceLocator. 59 protected abstract void ConfigureServiceLocator(); 60 // 61 // 摘要: 62 // Create the Microsoft.Practices.Prism.Logging.ILoggerFacade used by the bootstrapper. 63 // 64 // 备注: 65 // The base implementation returns a new TextLogger. 66 protected virtual ILoggerFacade CreateLogger(); 67 // 68 // 摘要: 69 // Creates the Microsoft.Practices.Prism.Modularity.IModuleCatalog used by Prism. 70 // 71 // 备注: 72 // The base implementation returns a new ModuleCatalog. 73 protected virtual IModuleCatalog CreateModuleCatalog(); 74 // 75 // 摘要: 76 // Creates the shell or main window of the application. 77 // 78 // 返回结果: 79 // The shell of the application. 80 // 81 // 备注: 82 // If the returned instance is a System.Windows.DependencyObject, the Microsoft.Practices.Prism.Bootstrapper 83 // will attach the default Microsoft.Practices.Prism.Regions.IRegionManager 84 // of the application in its Microsoft.Practices.Prism.Regions.RegionManager.RegionManagerProperty 85 // attached property in order to be able to add regions by using the Microsoft.Practices.Prism.Regions.RegionManager.RegionNameProperty 86 // attached property from XAML. 87 protected abstract DependencyObject CreateShell(); 88 // 89 // 摘要: 90 // Initializes the modules. May be overwritten in a derived class to use a custom 91 // Modules Catalog 92 protected virtual void InitializeModules(); 93 // 94 // 摘要: 95 // Initializes the shell. 96 protected virtual void InitializeShell(); 97 // 98 // 摘要: 99 // Registers the System.Types of the Exceptions that are not considered root 100 // exceptions by the Microsoft.Practices.Prism.ExceptionExtensions. 101 protected virtual void RegisterFrameworkExceptionTypes(); 102 // 103 // 摘要: 104 // Runs the bootstrapper process. 105 public void Run(); 106 // 107 // 摘要: 108 // Run the bootstrapper process. 109 // 110 // 参数: 111 // runWithDefaultConfiguration: 112 // If true, registers default Prism Library services in the container. This 113 // is the default behavior. 114 public abstract void Run(bool runWithDefaultConfiguration); 115 } 116 }
Bootstrapper初始化的顺序如下:
上图不难理解,软件记录日志,包括Bootstrapper的启动过程,所以Logger启动在第一位,生成和配置DI容器放在第三位,因为下面所有的操作依赖于使用容器解耦,,ModuleCatalog,并不依赖DI容器,可以放在第二位,下面的RegionAdapter和RegionBehavior也差不多意思,至于为什么Module放在最后,其实也无他,也是因为Module(模块)属于Shell(主窗体)。
因此,在使用Prism前,你必须先决定:
- 使用Unity或MEF,或其他DI容器。当然,如果使用其他注入容器,也决定了要自定义Bootstrapper。
- 你还可能需要把你程序的服务注册到container(DI容器),以方便各个Module(模块)的解释使用。
- 决定内置的日志组件是否适合,否则重写CreateLogger。
- 决定如何注册你的Module,使用配置文件还是XAML还是目录发现(需要在模块类使用特征标识 )还是直接写死在代码。
选择DI容器,很easy,熟悉哪种选哪种,使用也很简单,只需要继承一下就可以。
using System.Windows; using Microsoft.Practices.Prism.Modularity; using Microsoft.Practices.Unity; using Microsoft.Practices.Prism.UnityExtensions; namespace HelloWorld { class Bootstrapper : UnityBootstrapper { }
Bootstrapper是Prism的入口,因此,要指定APP.xaml的Bootstrapper
1 using System.Windows; 2 3 namespace HelloWorld 4 { 5 ///6 /// Interaction logic for App.xaml 7 /// 8 public partial class App : Application 9 { 10 protected override void OnStartup(StartupEventArgs e) 11 { 12 base.OnStartup(e); 13 Bootstrapper bootstrapper = new Bootstrapper(); 14 bootstrapper.Run(); 15 } 16 } 17 }
CreateShell
createShell是必须要继承的,因为必须指定主窗体。
class Bootstrapper : UnityBootstrapper { protected override DependencyObject CreateShell() { return this.Container.Resolve(); } }
这里使用DI容器的Resolve方法,这种方法的好处是把Shell所有需要的引用的DLL都自动引入。当然也可直接new一个主窗体对象出来。
进一步,可以使用ServiceLocator,ServiceLocator也是IOC的一种实现,类似DI也是IOC的一种实现。ServiceLocator最终还是调用DI容器,至于是Unity还是MEF,这是ServiceLocator要关心的事了,我们在这不作更深入的了解。
protected override DependencyObject CreateShell() { return ServiceLocator.Current.GetInstance(); }
InitializeShell
Shell初始化所需的工作应该写在这里。
protected override void InitializeShell() { Application.Current.MainWindow = Shell; Application.Current.MainWindow.Show(); }
当然也可以把所有初始化工作写到CreateShell()里,IntializeShell不重写,但总感觉有点怪怪的。
CreateModuleCatalog
在调用CreateModuleCatalog之前,Prism会调用CreateModuleCatalog,生成ModuleCatalog。使用模块化开发,需要实现CreateModuleCatalog方法添加Module。
protected override void ConfigureModuleCatalog() { base.ConfigureModuleCatalog(); ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog; moduleCatalog.AddModule(typeof(HelloWorldModule.HelloWorldModule)); }
ConfigureContainer
配置Container(DI容器),Container在Prism中具有非常重要的角色,在使用Prism开发的代码中,常常见到这个家伙。在Container的配置阶段,需要把核心服务注册到Container,当然也要把业务上的关键服务注册到Container。
基类代码实现如下:
1 protected virtual void ConfigureContainer() 2 { 3 this.Logger.Log(Resources.AddingUnityBootstrapperExtensionToContainer, Category.Debug, Priority.Low); 4 this.Container.AddNewExtension(); 5 6 Container.RegisterInstance (Logger); 7 8 this.Container.RegisterInstance(this.ModuleCatalog); 9 10 if (useDefaultConfiguration) 11 { 12 RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true); 13 RegisterTypeIfMissing(typeof(IModuleInitializer), typeof(ModuleInitializer), true); 14 RegisterTypeIfMissing(typeof(IModuleManager), typeof(ModuleManager), true); 15 RegisterTypeIfMissing(typeof(RegionAdapterMappings), typeof(RegionAdapterMappings), true); 16 RegisterTypeIfMissing(typeof(IRegionManager), typeof(RegionManager), true); 17 RegisterTypeIfMissing(typeof(IEventAggregator), typeof(EventAggregator), true); 18 RegisterTypeIfMissing(typeof(IRegionViewRegistry), typeof(RegionViewRegistry), true); 19 RegisterTypeIfMissing(typeof(IRegionBehaviorFactory), typeof(RegionBehaviorFactory), true); 20 RegisterTypeIfMissing(typeof(IRegionNavigationJournalEntry), typeof(RegionNavigationJournalEntry), false); 21 RegisterTypeIfMissing(typeof(IRegionNavigationJournal), typeof(RegionNavigationJournal), false); 22 RegisterTypeIfMissing(typeof(IRegionNavigationService), typeof(RegionNavigationService), false); 23 RegisterTypeIfMissing(typeof(IRegionNavigationContentLoader), typeof(UnityRegionNavigationContentLoader), true); 24 } 25 }
如果我们只是实现业务,不需要对Prism二次开发的话,对业务服务的注册,只需要重写ConfigureContainer即可。
class Bootstrapper : UnityBootstrapper { protected override void ConfigureContainer() { base.ConfigureContainer(); this.RegisterTypeIfMissing(typeof(IModuleTracker), typeof(ModuleTracker), true); this.Container.RegisterInstance(this.callbackLogger); } }
至此,Prism的初始化已介绍完毕。