zoukankan      html  css  js  c++  java
  • 二、从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

  • 相关阅读:
    Qt Creater更改默认构建目录
    QT-无法定位程序输入点解决方案
    Qt qmake报错(TypeError: Property 'asciify' of object Core::Internal::UtilsJsExtension)
    python学习--交互式图形编程实例二
    python学习--交互式图形编程实例一
    python学习--面向对象程序设计实例
    python学习--面向过程程序设计实例
    python学习--程序设计方法实例一
    python学习--字典操作实例二
    python学习--文档
  • 原文地址:https://www.cnblogs.com/duwenlong/p/15032031.html
Copyright © 2011-2022 走看看