[Prism]Composite Application Guidance for WPF(4)——Bootstrapper

来源:互联网 发布:淘宝网店铺购买 编辑:程序博客网 时间:2024/06/07 02:36

                              [Prism]Composite Application Guidance for WPF(4)——Bootstrapper

                                           周银辉

 

在默认情况下,WPF程序的启动方式APP的XAML中指定StartUri,然后IDE会自动帮我们生成一个Main方法,然后将StartUri中指定的窗口New一个出来,并作为应用程序的主窗口,但我们在Composite Application Guidance for WPF(3)——创建第一个Composite WPF Application (如果你不了解Prism的启动方式,那么建议你阅读) 中改变了这种方式:

        public App()
        {
            var boot = new Bootstrapper();
            boot.Run();
        }

 

而Bootstrapper类似于这样的类型:

 

    class Bootstrapper : UnityBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            var shell = new Shell();

            shell.Show();

            return shell;
        }

        protected override IModuleEnumerator GetModuleEnumerator()
        {
            var configStory = new ConfigurationStore();
            var enumerator = new ConfigurationModuleEnumerator(configStory);

            return enumerator;
        }
    }

其中这里的Shell实质上是我们应用程序的主窗口,可以看出来,其是在CreateShell()方法中将主窗口显示出来的,为什么要这样呢,那么我们就来看看Prism中的Bootstrapper

 

1,Bootstrapper是什么?

在Prism中,Bootstrapper是应用程序的启动器,其职责在于可以让你对应用程序的启动过程有着更好的控制.比如加载哪些模块,如何加载模块,注册哪些服务等等.在默认情况下Prism的UnityBootstrapper作为默认的加载器已经为你完成了很多工作,比如依赖注入容器的建立,Region映射,初始化模块的等,我们只要指定Shell和模块枚举器(IModuleEnumerator)便可以了,但很好的一点是,在Bootstrapper中很多方法都是虚方法(也包括抽象方法),我们可以通过重写这些方法来更改启动内容和启动逻辑.

 

2,Bootstrapper完成了哪些工作?

 

 

 上图是Prism的帮助文档给出了,从中我们可以看到其主要完成了4方面的工作:配置依赖注入容器,配置Region映射,创建Shell,初始化模块, 而打开Prism的源代码就更清晰了(在下面的Prism源代码中,我删除了一些可能会干扰视线的代码):

        public void Run(bool useDefaultConfiguration)
        {
            _useDefaultConfiguration = useDefaultConfiguration;
            //创建日志记录器
            ILoggerFacade logger = LoggerFacade;
        
            //创建默认容器
            Container = CreateContainer();
          
            //配置容器
            ConfigureContainer();

            //配置Region适配器映射
            ConfigureRegionAdapterMappings();

            //创建Shell
            DependencyObject shell = CreateShell();

            if (shell != null)
            {
                RegionManager.SetRegionManager(shell, Container.Resolve<IRegionManager>());
            }

            //初始化模块
            InitializeModules();

        }

 

2.1 创建日志记录器

Prism中自带了一个Logger,其原理很简单,利用的是Trace:

    public class TraceLogger : ILoggerFacade
    {
        /// <summary>
        /// 按照指定的 category 与 priority 记录一条新的日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="category">记录类型</param>
        /// <param name="priority">该条记录的优先级</param>
        public void Log(string message, Category category, Priority priority)
        {
            if (category == Category.Exception)
            {
                Trace.TraceError(message);
            }
            else
            {
                Trace.TraceInformation(message);
            }
        }
    }

在Prism中到处都能看到它的身影

 

2.2, 创建默认容器

依赖注入容器在Prism中(也包括其他Compsite Application框架,如CAB)扮演着最重要的角色,因为我们需要它来进行依赖注入(关于依赖注入,可以参考这里[转] 依赖注入&控制反转 ioC 容器和Dependency Injection 模式(中文版)) 

Prism在这个过程中主要完成的是一些基本组建和服务的注册

 

        protected virtual void ConfigureContainer()
        {
            //向容器注册日志实例
            Container.RegisterInstance(LoggerFacade);
            //容器注册自己
            Container.RegisterInstance(Container);
            //向容器添加一个扩展,其用于检查指定的类型是否已经在容器中注册
            Container.AddNewExtension<UnityBootstrapperExtension>();
            //模块枚举器
            IModuleEnumerator moduleEnumerator = GetModuleEnumerator();
            if (moduleEnumerator != null)
            {
                //向容器注册模块枚举器
                Container.RegisterInstance(moduleEnumerator);
            }

            //如果使用默认配置,则向容器注册CAL基础服务
            if (_useDefaultConfiguration)
            {
                RegisterTypeIfMissing(typeof (IContainerFacade), typeof (UnityContainerAdapter), true);
                RegisterTypeIfMissing(typeof (IEventAggregator), typeof (EventAggregator), true);
                RegisterTypeIfMissing(typeof (RegionAdapterMappings), typeof (RegionAdapterMappings), true);
                RegisterTypeIfMissing(typeof (IRegionManager), typeof (RegionManager), true);
                RegisterTypeIfMissing(typeof (IModuleLoader), typeof (ModuleLoader), true);
            }
        }

 

2.3 配置Region适配器映射
我们知道Region作为一个占位符,可以让其作为View的容器,而哪些控件类型具有此功能呢,至少我们知道ContentControl,ItemsControl等可以,事实上,只要有着对应Region适配器的都可以,而"配置Region适配器映射"便是将可以作为容器的控件类型与对应的适配器关联起来.

默认情况下,Prism为我们提供了3中适配器,也就对应着3种容器控件类型:Selector,ItemsControl,ContentControl,这3种控件类型以及其子类型都可以作为Region容器

        protected virtual RegionAdapterMappings ConfigureRegionAdapterMappings()
        {
            var regionAdapterMappings = Container.TryResolve<RegionAdapterMappings>();
            if (regionAdapterMappings != null)
            {
                //CAL默认提供的三种Region适配器
                regionAdapterMappings.RegisterMapping(typeof (Selector), new SelectorRegionAdapter());
                regionAdapterMappings.RegisterMapping(typeof (ItemsControl), new ItemsControlRegionAdapter());
                regionAdapterMappings.RegisterMapping(typeof (ContentControl), new ContentControlRegionAdapter());
            }

            return regionAdapterMappings;
        }

如果我们想要创建一种新的Region容器类型,那么我们需要做的是为该类型打造一个对应的XXXRegionAdapter(继承于RegionAdapterBase<T>类),然后重写ConfigureRegionAdapterMappings()方法并将容器类型和适配器注册起来就可以了.

 

2.4 创建Shell

 在默认的Bootstrapper UnityBootstrapper中,CreateShell是一个抽象方法,所以你必须自己定义Shell的创建过程,一般也来得非常简单,只要初始化你的Shell并返回就可以了:

        protected override DependencyObject CreateShell()
        {
            var shell = new Shell();

            shell.Show();

            return shell;
        }

 

2.5 初始化模块

对于模块的加载,Prism提供了几种方式,一是静态引用加载(和普通的程序集引用一样),二是动态加载(又分为扫描指定文件夹和读取配置文件两种);对应不同的加载方式就有着不同的模块加载器,在"初始化模块"这一步骤中最基本的便是取得模块加载器,然后在取得那些需要在引用程序启动时加载的模块,并将他们加载进来:

        protected virtual void InitializeModules()
        {
            var moduleEnumerator = Container.TryResolve<IModuleEnumerator>();
           

            var moduleLoader = Container.TryResolve<IModuleLoader>();
         
            ModuleInfo[] moduleInfo = moduleEnumerator.GetStartupLoadedModules();

 

            moduleLoader.Initialize(moduleInfo);
        }

 

关于模块加载器,后续随笔中将有专门的一节内容,敬请关注.

 

OK,今天先写这么多,非常感谢大家,周末愉快

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信限制加好友怎么办 珍爱网的客服老打电话怎么办 百合网的人气是怎么办 苹果x来电不显示怎么办 苹果8黑屏没反应怎么办 苹果六s开不了机怎么办 苹果6s突然黑屏怎么办 苹果6s黑屏了怎么办 苹果6s手机黑屏打不开怎么办 苹果6sp手机死机怎么办 苹果6s打不开机怎么办 6s开不了机怎么办 lg背光灯坏了怎么办 苹果6s屏幕变黄怎么办 苹果8背光坏了怎么办 苹果六背光坏了怎么办 苹果5s蓝屏死机怎么办 苹果6s突然黑屏怎么办? 苹果6s经常死机怎么办 苹果6s没有背光怎么办 苹果7白屏死机怎么办 苹果6p屏膜失灵怎么办 苹果7p屏幕卡死怎么办 苹果7p手机死机怎么办 苹果6s死机了怎么办啊 6s死机了关不了怎么办 爱疯7死机了怎么办 苹果11.4系统老死机怎么办 苹果6震动坏了怎么办 苹果6手机死机了怎么办 苹果x耗电太快怎么办 苹果6升级11.3卡怎么办 苹果6splus耗电快怎么办 苹果手机系统升级后反应慢怎么办 苹果8听筒声音小怎么办 苹果6s通话声音小怎么办 苹果手机通讯录丢失了怎么办 苹果换id通讯录没有了怎么办 华为p7 更新重启怎么办 打电话的图标没了怎么办 苹果手机wifi信号弱怎么办