程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Composite Application Guidance for WPF(4)——Bootstrapper

Composite Application Guidance for WPF(4)——Bootstrapper

編輯:關於.NET

在默認情況下,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);
    }

關於模塊加載器,後續隨筆中將有專門的一節內容,敬請關注.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved