我看prism的一点感受(一) 从Bootstrapper说起

       我是从09年开始接触Silverlight,当时是2.0版. 学习了一个月后,正好接到一个单子,就想用Silverlight来做前端界面.也是晕天暗地的一边做一边学.感谢园子里的老师们,我就是一边看他们的博客一边做项目的,其中特别感谢TerrLee,他的这篇文章<一步一步学silverlight 2 入门>带我进入了silverlight的世界.

     当后来我把这个项目部署到服务器上给客户使用时,出现了一个问题.我这个项目的Xap包达到了6M,有些客户在进入主界面时,居然要等几分钟才能下载完Xap包,当然是抱怨连天了,赶紧的解决的办法,后来在silverlight帮助文档里找到了关于按需下载的说明.照着它,我分割了项目,这样也算免强过关了. 

      在项目完工后,跟朋友聚会时,听说了有一个叫Prism的架框,可以用于silverlight的开发,具体如何当时也没有听懂.直到上个月,决定把去年做的那个项目升级,并把silverlight版本定为4.0版,想到了Prism这个框架,并想把这个框架应用到升级版。才开始了学习Prism的路程,这其中也少不了看园子里其他老师的博客。

      《从十个方面理解Prism和Silverlight》

      wpf && silverlight开发框架(prism)系列教程

      就是带我了解Prism的文章。

      当然,在学习这些文章的同时,我也把Prism Library的源码看了几遍,对其框架和意路也有自已的了解。

      为了不忘记我所学的这些知识,特地把学习的笔记抄录下来,放在博客里,可能过几年我再用到这个东西时,可以拿出来温故一下 。

===================================================================================== 

     Prism 是一个复合应用程序的框架。

      上面一句话里其实包含着三个信息,我们一个个来解释。

  1.  Prism是嘛东西?

 我查过google, google对此单词的解释是“棱镜”。哦,原来它是一面镜子,那原来上面一句话就可以说成是镜子是一个复合应用程序的  框架,其实这是不对的,微软对它的解释是” Composite Application Guidance for WPF and Silverlight.”  也就  是WPFSilverlight的复合应用程序指南,最新的Prism 4版,也包括了对Windows Phone 7 应用程序的复合应用支持

      2.什么是复合应用程序

            我猜想就是把一个程序拆分成几个程序,然后运行时再一个个拼凑起来,就成了复合程序了。

   3.框架

            把我们经常要用的类重新包装一遍,各个类都有互相调用,我们在写代码时调用这些类会少写很多代码?这就叫框架??


   从 bootstrapper 说起:

用过silverlight开发的朋友都知道,silverlight程序的启动是从App类的Application_Startup方法开始,这个方法里有一句代码


private   void   Application_Startup(object sender, StartupEventArgs e)
        {
            
this. RootVisual  = new MainPage();
}

     上面这段代码,就是程序启动后,实例化sliverlight项目中的MainPage这个类,再赋值给应用程序类(App)RootVisual属性,这样我们第一个看到的窗口就是MainPage页面了,MainPage一般是我们在Silverlight程序里定义第一个显示的页面。这段代码的功能就是让程序在启后,立马显示MainPage页面。

    

       但是使用Prism框架后,这段代码就发生了改变,程序启动后首先去实例化MyBootstrapper,然后调用MyBootstrapper的方法Run();

       private void Application_Startup(object sender, StartupEventArgs e)

        {

            MyBootstrapper boot = new MyBootstrapper();

            boot.Run();

        }

  现在这一改,就看不懂什么意思了,怎么没有要显示的页面???MyBootstrapper是什么类,Run方法又在干什么??

  坛子里有大师出来指点我们,MyBootstrapper是使用Prism框架要定义的第一个类,它是从Prism框架的UntiyBootstrapper类继承而来,我们需要重载这个基类的几个方法,就可以显示出界面来了。

 

 好,现在终于接触到Prism里面的东西了,那我们一起来看看UntiyBootstrapper到底是个什么类,它是干什么用的??

 

我们打开 Prism Library 源码一起来看看

      Untiybootstrapper类就定义在Prism.UntiyExtensions.Silverlight项目的UntiyBootstrapper.cs文件里,现在我们打开这个文件,看看里面的代码。

      呵呵,这个类的命名空间是Microsoft.Practice.Prism.UnityExtensions, 它继承于Bootstrapper类,又有一个基类,那里面的代码也不看了,接着找,看看Bootstrapper类是干什么的,Prism.Silverlight项目里有个Bootstrapper.cs文件,里面就是Bootstrapper类的定义。

 

    现在大家跟我一起进入到这个文件里一起看看。这个文件代码比较多,截图看不到完整的,我就给大家讲讲吧,这里面有些什么

ExpandedBlockStart.gif Bootstrapper类源码
public   abstract   class  Bootstrapper   // Bootstrapper是一个抽象类,就是说它不能实例化,你不能创建它的对象,它只能被继承
    {
         Protected  ILoggerFacade   Logger {  get set ; }    // 保护属性,是一个专门用来写日志的类
Protected  IModuleCatalog  ModuleCatalog {  get set ; }   // 模块目录,保护属性,是用来保存程序中所有要用到的模块信息
Protected  DependencyObject  Shell {  get set ; }   // Shell,一个依赖对象
以上三个属性具体是可以干什么,我们在后面列专题来说,这里大家只要知道这个类有这三个属性就可以了

protected   virtual  ILoggerFacade CreateLogger()   // 虚方法,用来创建LoggerFacade类的对象
{  
// 如果项目是silverlight的,就创建EmptyLogger对象,如果是WPF的,就创建TextLogger对象,它们都是ILoggerFacade接口的子类
            #if  SILVERLIGHT 
               
return   new  EmptyLogger();
           
#else
               
return   new  TextLogger();
           
#endif
        }

 
public   void  Run()   // 这是这个类的两个公共方法之一,我们在上面的示例代码中MyBootstrapper就是调用这个方法
        {   this .Run( true );}

       
public   abstract   void  Run( bool  runWithDefaultConfiguration);   // 抽象方法,等着人继承咧
protected   virtual  IModuleCatalog CreateModuleCatalog()    // 创建一个模块目录类的实例
        {  return   new  ModuleCatalog(); }

protected   virtual   void  ConfigureModuleCatalog(){}   // 虚方法,配置模块目录
  protected   virtual   void  RegisterFrameworkExceptionTypes()   // 虚方法,注册一个异常类型
        {
            ExceptionExtensions.RegisterFrameworkExceptionType(
                
typeof (Microsoft.Practices.ServiceLocation.ActivationException));
        }

        
protected   virtual   void  InitializeModules()   // 初始化模块,这里创建一个模块管理器接口的实例
        {
            IModuleManager manager  =  ServiceLocator.Current.GetInstance < IModuleManager > ();
            manager.Run();
        }
// 配置区域适配器映射,其实就是在这里事先申请哪些类型的控件可以做其它模块的容器,Silverlight可以使用四种控件来做为模块的容器,什么是区域,后面我们来解释
  protected   virtual  RegionAdapterMappings ConfigureRegionAdapterMappings()
        {
            RegionAdapterMappings regionAdapterMappings  =  ServiceLocator.Current.GetInstance < RegionAdapterMappings > ();
            
if  (regionAdapterMappings  !=   null )
            {
                
#if  SILVERLIGHT
           regionAdapterMappings.RegisterMapping( typeof (TabControl), ServiceLocator.Current.GetInstance < TabControlRegionAdapter > ());

                
#endif
                  regionAdapterMappings.RegisterMapping( typeof (Selector), ServiceLocator.Current.GetInstance < SelectorRegionAdapter > ());
                  regionAdapterMappings.RegisterMapping( typeof (ItemsControl), ServiceLocator.Current.GetInstance < ItemsControlRegionAdapter > ());
                  regionAdapterMappings.RegisterMapping( typeof (ContentControl), ServiceLocator.Current.GetInstance < ContentControlRegionAdapter > ());
            }

            
return  regionAdapterMappings;
        }

     
// 配置区域的行为
         protected   virtual  IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
        {
            var defaultRegionBehaviorTypesDictionary  =  ServiceLocator.Current.GetInstance < IRegionBehaviorFactory > ();

            
if  (defaultRegionBehaviorTypesDictionary  !=   null )
            {
                defaultRegionBehaviorTypesDictionary.AddIfMissing(AutoPopulateRegionBehavior.BehaviorKey,
                                                                  
typeof (AutoPopulateRegionBehavior));

                defaultRegionBehaviorTypesDictionary.AddIfMissing(BindRegionContextToDependencyObjectBehavior.BehaviorKey,
                                                                  
typeof (BindRegionContextToDependencyObjectBehavior));

                defaultRegionBehaviorTypesDictionary.AddIfMissing(RegionActiveAwareBehavior.BehaviorKey,
                                                                  
typeof (RegionActiveAwareBehavior));

                defaultRegionBehaviorTypesDictionary.AddIfMissing(SyncRegionContextWithHostBehavior.BehaviorKey,
                                                                  
typeof (SyncRegionContextWithHostBehavior));

                defaultRegionBehaviorTypesDictionary.AddIfMissing(RegionManagerRegistrationBehavior.BehaviorKey,
                                                                  
typeof (RegionManagerRegistrationBehavior));

                defaultRegionBehaviorTypesDictionary.AddIfMissing(RegionMemberLifetimeBehavior.BehaviorKey,
                                                  
typeof (RegionMemberLifetimeBehavior));

            }

            
return  defaultRegionBehaviorTypesDictionary;
        }
       
// 创建Shell
protected   abstract  DependencyObject CreateShell();
      
// 初始化Shell
         protected   virtual   void  InitializeShell();
       
// 配置服务定位类
        protected   abstract   void  ConfigureServiceLocator();
    }

 

看了上面这些代码,估计不少人会头晕眼花,不知道这是干嘛的,其实我们不必考虑那么多,因为这个类是个抽象类,它始终是要被子类继承的,作为子类最关心的是,我能继承些什么下来,需要重载些什么方法

   所以我们只需要知道几点就行:

    1.     这个类里有些什么东西(主要是属性

    2.     这个类里做了些什么(哪些方法是实现了,子类是可以不用重载的)

    3.     这个类没有做什么(哪些方法没有实现,子类需要重载)

 

   下面我就来回答

    1 该类里面定义了三个属性Logger, ModuleCatalog, Shell。这三个属性都是受保护的成员,只能在类的内部和子类的内部使用

      logger 是用来写日志,prism 的每一步操作都会记录下来

      ModuleCatalog 见名思意是模块目录的意思,其实它里面就是一个列表,把项目中要加载的每个模块的信息给保存起来。当初始运行prism时,ModuleManager这个类的实例会读取ModuleCatalog里面保存的所有模块的信息(比方说,是哪个xap文件,里面模块命名空间是什么,模块的类型名是什么,这个模块是否依赖于其他的模块,这模是否在程序初始化时就下载,还是留在以后程序运行的过程中,想下载的时候再下载) 

     Shell  是一个依赖对象类型,其实它在后面代码中的作用是保存Mainpage的引用

 

    2 类代码里定义了实例化Logger,ModuleCatalog两个属性的方法,也就是说,只要子类调用这两个方法,就可以创        建Logger,ModuleCatalog两个属性的对象,可以拿着用了.

    实现了区域控件的定义,区域行为的定义,和创建IModuleManager接口的实现代码

 

      3 没有做的事,这是我们最关心的,它没有实现,那么子类就要去实现他。

            没有实现的有

  public abstract Run(Bool) 方法

   virtual void ConfigureModuleCatalog(){}

  protected abstract DependencyObject CreateShell();

          protected virtual void InitializeShell()

           protected abstract void ConfigureServiceLocator();

     所以等会我们看UntiyBootstrapper类时,一定要关注

 

         

好了,接下来,我们再看看 UntiyBootstrapper 类里面做了些什么事
ExpandedBlockStart.gif UntiyBootstrapper源码
public   abstract   class  UnityBootstrapper : Bootstrapper   // 好家伙,这也是个抽象类,不能直接拿来用的,还得继承呀
    {
        
private   bool  useDefaultConfiguration  =   true ;   // 是否使用默认的配置
   public  IUnityContainer Container {  get protected   set ; }   // 容器属性,这个容器是用来实例化对象的。具体怎么实例化后面再来讲

 
public   override   void  Run( bool  runWithDefaultConfiguration)   // 呵呵,一上来就实现父类的Run(bool) 方法
        {
            
this .useDefaultConfiguration  =  runWithDefaultConfiguration;  
 
this .Logger  =   this .CreateLogger();  // 创建日志类实例,这是调用了父类的方法
             this .ModuleCatalog  =   this .CreateModuleCatalog();   // 创建模块目录类实例,这是调用父类的方法
            
// Logger, ModuleCatalog就是父类里面三个属性之二。
  this .ConfigureModuleCatalog();   // 配置模块目录,这是父类里没有实现的虚方法,在这个类里也没有实现,等着下一个子类去实现了
     this .Container  =   this .CreateContainer();   // 实例化依赖注入容器类,这是本类的方法,实现了
             this .ConfigureContainer();   // 配置容器,这是本类的方法,实现了
this .ConfigureServiceLocator();   // 配置服务定位,这是本类的方法,实现了
  this .ConfigureRegionAdapterMappings();   // 配置区域适配器映射,这是调用父类的方法,在父类里已实现
  this .ConfigureDefaultRegionBehaviors();   // 配置区域行为,这是调用父类的方法,在父类里已实现

           
            
this .RegisterFrameworkExceptionTypes(); // 注册框架异常类型,这是在本类里重载了父类已实现的方法
  this .Shell  =   this .CreateShell();   // 创建Shell视图,这是父类没有实现的方法,在本类也没有实现,得等着它的子类去实现了
             if  ( this .Shell  !=   null )
            {
              RegionManager.SetRegionManager( this .Shell,  this .Container.Resolve < IRegionManager > ());   // 设置区域管理器
 RegionManager.UpdateRegions(); // 区域管理器更新区域
  this .InitializeShell(); // 初始化Shell,这是父类里没有实现地方法,本类也没有实现
            }
            
            
if  ( this .Container.IsRegistered < IModuleManager > ())
            {
 
this .InitializeModules();  // 初始化模块,就是创建一个modulemanager管理器的对象
            }
  }

 

     这里呢,笔者偷了个懒,UntiyBootstrapper类的其他方法没有列出来,只列出了Run()方法,一来是该类其他的方法都是在Run里被调   用,等会笔者在介绍Run方法,也会详细介绍其他方法的,二来我还是最关心的是上面用红色标注释的方法,这些得在子类里实现呀,其他的方法就暂时不管了。

 

     好了,介绍到这里,Prism框架里面首当其中的两个类Bootstrapper, UntiyBootstrapper都出场了,现在接下来该我们来写代码了。

Prism的文档介绍,在我们的应用程序里首先要继承UntiyBootstrapper类,实现其中几个方法的重载,用来加载我们的应用程序中的模块和指定初始显示的视图。继承是一定要的,那么重载哪个方法咧,就是上面用红色标注的几个方法,接下来看代码

ExpandedBlockStart.gif MyBootstrapper
Class  MyBootstrapper:UntiyBootstrapper
{
// 重载父类的方法,加载一个模块,并返回ModuleCatalog对象
    protected   override  IModuleCatalog CreateModuleCatalog()
        {
               
return  Microsoft.Practices.Prism.Modularity.ModuleCatalog.CreateFromXaml(
                
new  Uri(“模块名”, UriKind.Relative));
        }
        
// 重载父类的方法,创建一个MainPage的实例,看到这里,会心一笑,原先在Application_Startup(object sender, StartupEventArgs e)方法里面实例化MainPage移到这里来了
         protected   override  DependencyObject CreateShell()
        {
                MainPage view  =   this .Container.TryResolve < MainPage > ();
     
return  view;
              }
protected   override   void  InitializeShell()
{ // 给应用程序的RootVisual 属性赋值,这也是Application_Startup(object sender, StartupEventArgs e)方法的原始代码
    Application.Current.RootVisual  =  Shell;
}
}

 

     看到这里,我们再回过头来,看看文章开始的示例代码,再一起回味一下MyBootstrapper类的执行过程。

原先的代码

private   void   Application_Startup(object sender, StartupEventArgs e)

        {

            this. RootVisual  = new MainPage();

}

在整个应用程序启动后,会触发App.Startup事件,并调用Application_Startup方法,在这个方法里,我们首先实例化一个MainPage类,这个类就是我们首先要显示的Xaml文件,接下来把这个实例引用赋值给this.RootVisual,这样在程序启动后,就会显示MainPage页面了。

    

现在我改成这样的代码

   private void Application_Startup(object sender, StartupEventArgs e)

        {

            MyBootstrapper boot = new MyBootstrapper();

            boot.Run();

        }

那个这个代码会怎么做呢,它首先会实例化MyBootstrapper的父类的父类Bootstrapper类,在栈里分配了三个属性的引用变量的空间,也就是

Logger

ModuleCatalog

Shell

这三个类型的引用。

接下来,实例化它的父类UntiyBootstrapper,为UntiyBootstrapper的两个属性成员分配空间,

bool useDefaultConfiguration  值变型变量

IUnityContainer Container  依赖注入容器对象的引用。

 

最后就是调用boot.Run()这个方法了,而这个方法又是调用Run(bool)  方法,所以我们还是再看看这个方法里面的代码是什么执行的了。

     第一步 this.Logger = this.CreateLogger(); //创建日志类实例,这是调用了Bootstrapper类的方法

    第二步  this.ModuleCatalog = this.CreateModuleCatalog();  //创建模块目录类实例,这个方法在MyBootstrapper重载,把一个具体的模块加入到ModuleCatalog对象里,并返回ModuleCatalog对象的引用

  第三步  this.ConfigureModuleCatalog(); 这个方法在所有的类里都没去实现它,但也不影响程序运程

  第四步 this.Container = this.CreateContainer();  //实例化依赖注入容器类,这是调用了UntiyBootstrapper 类的方法实例化Container

  第五步 this.ConfigureContainer();  //配置容器,这是调用了UntiyBootstrapper 类的方法实现

  第六步this.ConfigureServiceLocator();  //配置服务定位,这是调用了UntiyBootstrapper 类的方法实现

  第七步 this.ConfigureRegionAdapterMappings();  //配置区域适配器映射,这是调用Bootstrapper的方法,在Bootstrapper类里实现指定哪些控件可以作为模块的容器

  第八步 this.ConfigureDefaultRegionBehaviors();  //配置区域行为,这是调用Bootstrapper的方法,在Bootstrapper类里已实现

  第九步 this.Shell = this.CreateShell();  //这个很重要,在MyBootstrapper类里实现,就是创建一个MainPage页面的对象,并把这个实例的引用赋值给Shell属性(Shell是在Bootstrapper类里定义的)

            if (this.Shell != null)

            {

                 RegionManager.SetRegionManager(this.Shell, this.Container.Resolve<IRegionManager>());  //把视图和区域关联起来

 RegionManager.UpdateRegions();//区域管理器更新区域,其实是触发一个事件,通知框架区域已设置好

 this.InitializeShell();//初始化Shell,这是在MyBootstrapper类里实现,就是把MainPage设置为首先显示的页面

            }

           

            if (this.Container.IsRegistered<IModuleManager>())

            {

这是第十步 this.InitializeModules(); //初始化模块,就是创建一个modulemanager管理器的对象

            }

 

 



  

转载于:https://www.cnblogs.com/jasson/archive/2010/11/25/1887459.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值