二、從GitHub瀏覽Prism示例代碼的方式入門WPF下的Prism之Modules的幾種加載方式


這一篇梳理Prism中07示例Module的幾種加載方式。

07示例分為了5個,有5種不同的Module加載方式。

我們開始學習加載Modules

觀察07-Modules-Appconfig示例

分為ModuleA工程和Modules工程

我們在解決方案上打開管理解決方案的Nuget程序包,ModuleA工程引用了Prism.Wpf;Modules引用了Prism.Unity;

Modules的App.config下配置文件被修改了。我們先不分析,就看一下結構。

<configuration>
  <configSections>
    <section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf" />
  </configSections>
  <startup>
  </startup>
  <modules>
    <module assemblyFile="ModuleA.dll" moduleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleAModule" startupLoaded="True" />
  </modules>
</configuration>

1、ModuleA工程

ModuleA工程引用了Prism.Wpf。

1.1、新建ModuleAModule.cs

ModuleAModule類繼承自IModule,該接口包含2個 方法OnInitialized和RegisterTypes;ModuleAModule中實現OnInitialized方法時使用了IContainerProvider調用了Resolve ();

還有印象在第一篇中我們整理的,IRegionManager是一個區域管理,用於綁定區域和視圖的,而這里就在做把ViewA使用regionManager的RegisterViewWithRegion()方法,向ContentRegion字符串對應的區域注冊ViewA視圖。通過上一篇的學習,我們知道這樣就能直接把ViewA放在ContentRegion的區域,我們先不管邏輯實現。因為我們看到了配置文件中有這一塊的內容,先不看。

  var regionManager = containerProvider.Resolve<IRegionManager>();
            regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));

1.2、新建Views下的ViewA自定義控件,在Views的ViewA中只有一個顯示控件顯示了View A 字號為38。

2、Modules工程

Modules工程引用了Prism.Unity。

2.1App.xaml

添加命名空間xmlns:prism="http://prismlibrary.com/"

修改Application為prism:PrismApplication

取消StartupUri屬性

2.2App.cs

繼承類由Application修改為PrismApplication

重寫CreateShell()方法,通過Container.Resolve解析MainWindow並返回,作為啟動窗體;

重寫RegisterTypes方法

重寫CreateModuleCatalog(),返回一個ConfigurationModuleCatalog()對象。

 protected override IModuleCatalog CreateModuleCatalog()
        {
            return new ConfigurationModuleCatalog();
        }

2.3Views下的MainWindow.xaml

有一個ContentControl顯示控件,設置了附加依賴項屬性,區域名稱為ContentRegion。MainWindow.cs無特殊修改。

2.4運行代碼,界面顯示View A

總結:在Modules中做修改了App.config,設置了ConfigSections,我按照命名空間找過去,是使用ConfigurationStore配置Modules的。同時在App.config中也有配置的modules。里面寫了assemblyFile、moduleType、moduleName、startupLoaded。也就是說這種方式是使用config配置文件的方式加載Modules,然后再對應的ModuleA或者其他名稱的DLL中就可以通過containerProvider,和RegionManager來設置區域和視圖的關聯,但是客戶端軟件不推薦這種方法,因為客戶端安裝再客戶電腦上,他可以通過自己修改app.config可以加載不同的模塊。這樣徹底解耦了DLL和主工程的引用關系。

觀察07-Modules-Code示例

同樣分為ModuleA和Modules兩個工程,Modules工程引用了Prism.Unity;ModuleA工程引用了Prism.Wpf;

1、ModuleA工程

ModuleA工程引用了Prism.Wpf

1.1、新建ModuleAModule.cs

ModuleAModule類繼承自IModule接口。並實現了該接口的2個方法,OnInitialized()、RegisterTypes,並再OnInitialized()方法中使用容器代理解析了IRegionManager,然后關聯區域和顯示界面。用於呈現。

1.2、Views下的ViewA.xaml

只包含了顯示控件,顯示View A,字號為38;

2、Modules工程

Moudules工程引用了Prism.Unity、ModuleA兩個工程;

2.1、App.xaml

添加命名空間:xmlns:prism="http://prismlibrary.com/"

修改了Application為PrismApplication

去掉了StartupUri屬性

2.2App.cs

App修改繼承自PrismApplication

重寫CreateShell()方法使用Container.Resolve解析MainWindow作為啟動窗體;

重寫RegisterTypes(不重寫編譯就報錯)

重寫ConfigureModuleCatalog方法

  protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {
            moduleCatalog.AddModule<ModuleA.ModuleAModule>();
        }

使用傳入的moduleCatalog對象的AddModule方法,傳入了ModuleA工程的ModuleAModule類型。

對比了上一篇appconfig篇,我們發現再App.cs中的ConfigureModuleCatalog方法是加載Module的。不同的加載類型,這里都需要重寫這個方法。而使用Code加載Module的方法還需要引用工程。

2.3Views下的MainWindow.xaml

設置了ContentControl顯示控件,並設置了附加依賴項屬性用於設置區域名稱為ContentRegion,后台cs中無額外代碼

2.4運行Modules工程

界面顯示View A。

總結:創建了ModuleA工程、Modules主工程,ModuleA引用了Prism.Wpf;主工程引用了Prism.unity;ModuleA兩個工程,主工程通過引用項目的方式引入MouduleA,然后再通過重寫PrismApplication的ConfigureModuleCatalog()加載了ModuleA下的ModuleAModule類。ModuleAModule類實現了IModule的OnInitialized()方法,並再該方法關聯區域和顯示視圖,用於顯示內容。這種加載方式感覺會比第一種好一些,我們繼續往下看下一個例子。

觀察07-Modules-Directory示例

分為ModuleA和Modules兩個工程,ModuleA工程引用了Prism.Wpf、Modules工程引用了Prism.Unity;

1、ModuleA工程

ModuleA工程引用了Prism.Wpf;

1.1、新建了ModuleAModule.cs類

ModuleAModule繼承自Prism.Modularity.IModule,並實現了OnInitialized()、RegisterTypes()

OnInitialized()方法同樣使用傳入的IContainerProvider容器代理對象Resolve解析出IRegionManager,然后使用這個RegionManager對象去關聯一個區域和視圖。

1.2、Views下的ViewA.xaml

和其他工程一樣,包含一個顯示控件顯示一個ViewA 字號為38;cs文件中無新增代碼。

2、Modules工程

Modules工程引用了Prism.Unity;

2.1、App.xaml

新增命名控件xmlns:prism="http://prismlibrary.com/"

修改Application為PrismApplication;

去掉StartupUri屬性

2.2、App.cs

修改App繼承自PrismApplication;

重寫CreateShell()使用Container.Resolve()解析MainWindow用作啟動窗體;

重寫RegisterTypes() 不重寫編譯失敗。

重寫CreateModuleCatalog()方法

  protected override IModuleCatalog CreateModuleCatalog()
        {
            return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
        }

實例化了DirectoryModuleCatalog並傳入了路徑.\Modules,因為是從目錄加載的,這里不知道是不是固定寫法,然后所有自己創建的Module只要繼承自IModule就行嗎?這里沒有驗證,只是學習知道了可以從目錄加載。繼續往下。

3.1、Views下的MainWindow.xaml

包含了一個顯示控件同時設置了附加依賴項屬性區域名稱ContentRegion。cs文件無新增代碼。

4、先編譯ModuleA、然后再運行Modules程序,不然報錯;

界面顯示View A

總結:使用Directory加載Module的話,再主工程中不需要引用各個Module,只需要配置目錄的路徑即可,但是沒有驗證新增ModuleB、C等等,是否可以自動加載進來,這個可以結合第一篇的代碼,使用Resolve資源配合創建按鈕,再各個Module中Activate和Deactivate修改主工程中區域名稱對應的顯示內容。

觀察07-Modules - LoadManual示例

包含ModuleA和Modules兩個工程;ModuleA引用了Prism.Wpf包;Modules引用了Prism.Unity包;

1、ModuleA工程

ModuleA工程只引用了Prism.Wpf;

1.1、新增ModuleAModule.cs

ModuleAModule繼承自Prism.Modularity.IModule,並實現了OnInitialized()和RegisterTypes()接口,OnInitialized()方法和前面的項目一樣,同樣使用IContainerProvider容器代理Resolve解析RegionManager()對象,然后使用regionManager關聯區域名稱和對應的視圖,用於顯示。

1.2、Views下的ViewA.xaml

包含用於顯示的TextBlock控件。顯示內容為View A ,字號為38,cs文件中無修改;

2、Modules工程

Modules工程引用了Prism.Unity;和ModuleA項目;

2.1、App.xaml

增加命名空間prism="http://prismlibrary.com/"

修改Application為PrismApplication

去掉StartupUri屬性

2.2App.cs

修改App繼承自PrismApplication;

重寫CreateShell()方法;

使用Container.Resolve()方法設置啟動窗口為MainWindow。

重寫RegisterTypes()方法,不重寫編譯報錯。

重寫ConfigureModuleCatalog()方法

        protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {
            var moduleAType = typeof(ModuleAModule);
            moduleCatalog.AddModule(new ModuleInfo()
            {
                ModuleName = moduleAType.Name,
                ModuleType = moduleAType.AssemblyQualifiedName,
                InitializationMode = InitializationMode.OnDemand
            });
        }

再添加ModuleA的工程引用后,直接使用typeof讀取ModuleAModule。然后再moduleCatalog中使用AddModule方法,新建一個ModuleInfo()對象,包含了,Module的名稱、限定名稱、加載方式為按需加載;

2.3、Views下的MainWindow.xaml

設置了一個ContentControl 顯示控件,並設置了附加依賴項屬性用於關聯顯示區域ContentRegion。

添加了一個Button,注冊了Click事件;

2.4、Views下的MainWindow.cs

我們來到CS文件中,我們看到了構造函數中初始化 IModuleManager對象,然后再用戶點擊Button的時候,使用LoadModule()方法加載ModuleAModule。

3、先編譯ModuleA,再運行Modules

我們看到啟動后,顯示Load Module的Button,點擊這個Button后顯示View A文字。

總結:再Modules工程中,引入了Prism.Unity和ModuleA,再ModuleA中引用Prism.Wpf。

想使用LoadManual加載的方式,在App.cs中重寫ConfiureModuleCatalog()方法時,獲取typeof對應的ModuleA工程下的類對象,然后配置對應的程序集信息,在需要的地方,使用_moduleManager下的LoadModule()方法去加載對應的Module,各個Module去實現自己的IModule,用於在OnInitialized()中關聯區域和視圖。

觀察07-Modules - Xaml示例

包含ModuleA工程和Modules工程兩個工程,ModuleA引用了Prism.Wpf包、Modules引用了Prism.Unity包和ModuleA項目;

1、ModuleA工程

添加了對Prism.Wpf包的引用;

1.1、創建了ModuleAModule.cs類,繼承了Prism.Modularity.IModule接口,實現了OnInitialized()和RegisterTypes()方法,並在OnInitialized()方法中使用傳入的IContainerProvider對象調用Resolve發方法解析IRegionManager對象。然后使用IRegionManager的實例來關聯字符串為ContentRegion和ViewA視圖,用於顯示。

1.2、Views下創建了用戶自定義控件ViewA.xaml

里面有一個用戶顯示內容的TextBlock控件,顯示內容為View A字號為38,cs文件中無新增內容

2、Modules工程

Modules引用了Prism.Unity包和ModuleA工程;

2.1、App.config

在App.config中添加了configSections節點,里面配置了Prism.Modularity.ModulesConfigurationSection和Modules節點,

用於添加引用Prism下的庫,和加載ModuleA.dll的配置項;

2.2、App.xaml

添加了命名空間xmlns:Prism:="http://prismlibrary.com"

修改Application為PrismApplication

去掉StartupUri屬性

2.3App.cs

修改App繼承自PrismApplication

重寫CreateShell()方法,使用Container.Resolve解析MainWindow,並返回做為啟動窗體。

重寫RegisterTypes()

重寫CreateModuleCatalog()

使用XamlModuleCatalog()方法,傳入URI。URI文本是當前工程的ModuleCatalog.xaml資源文件作為IModuleCatalog。

2.3ModuleCatalog.xaml

添加命名空間xmlns:m="clr-namespace:Prism.Modularity;assembly=Prism.Wpf"

修改根節點為m:ModuleCatalog,添加子節點m:ModuleInfo.並包含了ModuleA工程的信息。

<m:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:m="clr-namespace:Prism.Modularity;assembly=Prism.Wpf">

    <m:ModuleInfo ModuleName="ModuleAModule" 
                  ModuleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

</m:ModuleCatalog>

2.4Views下的MainWindow.xaml

包含了一個用於顯示的ContentControl控件,添加了附加依賴項屬性RegionName。cs代碼無新增

先編譯ModuleA,在運行Modules

我們看到了界面顯示View A

總結:ModuleA工程引用Prism.Wpf包,通過繼承自Prism.Modularity.IModule接口,並重寫OnInitialized()方法獲取RegionManager的對象,用來在ModuleA工程中關聯顯示區域Region和視圖;在主工程Modules中添加Prism.Unity和ModuleA工程;

App.cs中重寫CreateModuleCatalog()方法,並創建XamlModuleCatalog對象關聯創建的ModuleCatalog.xaml資源文件,同時App.config中也引用ModuleA.dll配置。

ModuleCatalog.xaml資源文件設置ModuleCatalog和ModuleInfo來管理引用的Module工程。我嘗試了刪除App.config內容和工程,發現會報錯。所以必須包含以上內容。

我們打開WPFPrismDemo工程,挑選前面5種加載方式的其中一種,寫自己的加載代碼。

我選擇了07-Modules - Code這個示例用來加載代碼;

我選擇的原因是ModuleA,還是解耦后獨立出來的工程,和主工程的關聯關系就是主工程下引用,然后再App.cs下通過重寫configureModuleCatalog()方法,加載對應的Module模塊。關聯關系就創建了。沒有額外的操作,也不需要完整加載目錄。不要參考前面的代碼,如果忘記了,可以上去看一下,回憶一下你選擇的加載方式,然后我們開始寫:

再WPFPrismDemo工程上,新建一個類庫工程ModuleSalesForecast模塊,是我們的銷售預測模塊,用於解耦銷售數據顯示和銷售預測顯示根其他模塊的重疊,主要是報表功能。

ModuleSalesForecast引用Prism.Wpf;

新建ModuleSalesForecastModule類,並繼承Prism.Modularity.IModule接口.

重寫OnInitialized()方法時關聯SalesForecastRegion(還未定義)區域和創建的Views下的ViewSalesForecast.xaml(還未定義)。

using ModuleSalesForecast.Views;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;

namespace ModuleSalesForecast
{
    public class ModuleSalesForecastModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            var regionManager = containerProvider.Resolve<IRegionManager>();
            regionManager.RegisterViewWithRegion("SalesForecastRegion", typeof(ViewSalesForecast));
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
           
        }
    }
}

新建Views文件夾

新建ViewSalesForecast.xaml

目前就放置一個TextBlock,顯示為預測今年銷售額全是第二。大小等於38;

ModuleSalesForecast工程部分我們目前就完成了

接下來是WPFPrismDemo部分

再WPFPrismDemo工程引用ModuleSalesForecast工程

打開App.cs

重寫ConfigureModuleCatalog()方法

並調用AddModule方法,解析ModuleSalesForecastModule;

using Prism.DryIoc;using Prism.Ioc;using Prism.Modularity;using System.Windows;namespace WPFPrismDemo{    /// <summary>    /// App.xaml 的交互邏輯    /// </summary>    public partial class App : PrismApplication    {        protected override Window CreateShell()        {            return Container.Resolve<MainWindow>();        }        //這個方法如果不重寫則會編譯報錯。        protected override void RegisterTypes(IContainerRegistry containerRegistry)        {        }        protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)        {            base.ConfigureModuleCatalog(moduleCatalog);            moduleCatalog.AddModule<ModuleSalesForecast.ModuleSalesForecastModule>();        }    }}

在主窗體的MainWindow中,我們基於上一個例子,修改代碼如下,增加用於顯示的ContentControl ,並設置附加依賴項屬性RegionName為SalesForecastRegion。

<Window x:Class="WPFPrismDemo.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"        xmlns:prism="http://prismlibrary.com/"        xmlns:local="clr-namespace:WPFPrismDemo"        mc:Ignorable="d"        Title="MainWindow" Height="450" Width="800">    <DockPanel >        <StackPanel>            <Button Content="Activate View A" Click="ActivateViewA_Click"/>            <Button Content="Deactivate View A" Click="DeactivateViewA_Click"/>            <Button Content="Activate View B" Click="ActivateViewB_Click"/>            <Button Content="Deactivate View B" Click="DeactivateViewB_Click"/>        </StackPanel>         <ContentControl prism:RegionManager.RegionName="ContentRegion" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center"/>        <ContentControl prism:RegionManager.RegionName="SalesForecastRegion"/>    </DockPanel></Window>

運行一下我們的代碼:觀察結果

依次是StackPanel中的按鈕,和ViewA和ViewB切換的視圖,和預測分析的視圖。從這一篇Modules不同的加載方式就梳理完了。

繼續往后學習,07示例結束了,還有22個示例沒有學習;

我創建了一個C#相關的交流群。用於分享學習資料和討論問題。歡迎有興趣的小伙伴:QQ群:542633085


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM