Prism_06_Modules

通常,为了构建一个低耦合、高内聚的应用程序,我们一般选择分层。WPF通过MVVM模式将程序分为 View-ViewModel-Model ,很大程度上消除了业务逻辑和界面元素之间的高耦合,使得开发人员将更多精力放在业务逻辑层面,UI界面可以交给更专业的UI人员。

通常,一个应用程序由不同的业务模块来组合而成,理想情况下,每个业务模块有独立的功能;业务模块之间是低耦合关系的;每个业务模块能够单独来开发测试和部署。这样程序是非常容易扩展、测试和维护,而Prism提供了将程序模块化的功能。

下图是Prism中具有多个模块的程序设计:
在这里插入图片描述

IModule

模块是功能和资源的逻辑集合,可以单独开发、测试、部署和集成到应用程序中。每个模块都有一个中心类,负责初始化模块并将其功能集成到应用程序中,该类实现了 IModule 接口。

首先,当模块被加载时,RegisterTypes 首先被调用来注册模块实现的任何服务和功能。

然后,调用 OnInitialized 方法,执行View 的注册或其他初始化代码。

public class MyModule : IModule
{
    public void RegisterTypes(IContainerRegistry containerRegistry)
    {
        // register with the container that SomeService implements ISomeService
        // ISomeService is defined in the Infrastructure module, see app architecture diagram
        containerRegistry.Register<MyApplication.Infrastructure.ISomeService, SomeService>();
    }

    public void OnInitialized(IContainerProvider containerProvider)
    {
        // use the containerProvider to retrieve the instance of the Prism RegionManager
        // and register the view in this module with a specific region in the app
        var regionManager = containerProvider.Resolve<IRegionManager>();
        regionManager.RegisterViewWithRegion("MyModuleView", typeof(Views.ThisModuleView));
    }
}

ModuleCatalog

ModuleCatalog 保存着程序可以使用的模块信息,本质上是 ModuleInfo 的集合。创建 ModuleInfo 的方法有以下几种:

  • 在代码中注册
  • 在XAML中注册
  • 在配置文件中注册
  • 在磁盘中发现
在代码中注册
protected override void ConfigureModuleCatalog()
{
    Type moduleCType = typeof(ModuleC);
    ModuleCatalog.AddModule(new ModuleInfo()
    {
        ModuleName = moduleCType.Name,
        ModuleType = moduleCType.AssemblyQualifiedName,
        InitializationMode = InitializationMode.OnDemand, // 按需加载
    });
}

还需要使用 Prism 提供的声明属性:

[Module(ModuleName = "ModuleA")]
[ModuleDependency("ModuleD")]
public class ModuleA : IModule
{
}
在XAML中注册

通常 .xaml 文件作为资源添加到 shell 项目中。ModuleCatalog 是由 App 通过调用 CreateFromXaml 方法创建。

<--! ModulesCatalog.xaml -->
<Modularity:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:Modularity="clr-namespace:Microsoft.Practices.Prism.Modularity;assembly=Microsoft.Practices.Prism">

    <Modularity:ModuleInfoGroup Ref="file://DirectoryModules/ModularityWithMef.Desktop.ModuleB.dll" InitializationMode="WhenAvailable">
        <Modularity:ModuleInfo ModuleName="ModuleB" ModuleType="ModularityWithMef.Desktop.ModuleB, ModularityWithMef.Desktop.ModuleB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </Modularity:ModuleInfoGroup>

    <Modularity:ModuleInfoGroup InitializationMode="OnDemand">
        <Modularity:ModuleInfo Ref="file://ModularityWithMef.Desktop.ModuleE.dll" ModuleName="ModuleE" ModuleType="ModularityWithMef.Desktop.ModuleE, ModularityWithMef.Desktop.ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <Modularity:ModuleInfo Ref="file://ModularityWithMef.Desktop.ModuleF.dll" ModuleName="ModuleF" ModuleType="ModularityWithMef.Desktop.ModuleF, ModularityWithMef.Desktop.ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
            <Modularity:ModuleInfo.DependsOn>
                <sys:String>ModuleE</sys:String>
            </Modularity:ModuleInfo.DependsOn>
        </Modularity:ModuleInfo>
    </Modularity:ModuleInfoGroup>

    <!-- Module info without a group -->
    <Modularity:ModuleInfo Ref="file://DirectoryModules/ModularityWithMef.Desktop.ModuleD.dll" ModuleName="ModuleD" ModuleType="ModularityWithMef.Desktop.ModuleD, ModularityWithMef.Desktop.ModuleD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</Modularity:ModuleCatalog>

ModuleInfoGroups 方便对同一程序集中的模块进行分组。在 ModuleInfoGroups 中可以定义模块间依赖。

protected override IModuleCatalog CreateModuleCatalog()
{
    return ModuleCatalog.CreateFromXaml(new Uri("/MyProject;component/ModulesCatalog.xaml", UriKind.Relative));
}
配置文件

可以在 App.config 文件中指定模块信息,此时在运行时添加或删除模块变得容易,而无需再重新编译程序。

<!-- ModularityWithUnity.Desktop\\app.config -->
<xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf"/>
    </configSections>

    <modules>
        <module assemblyFile="ModularityWithUnity.Desktop.ModuleE.dll" moduleType="ModularityWithUnity.Desktop.ModuleE, ModularityWithUnity.Desktop.ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleE" startupLoaded="false" />
        <module assemblyFile="ModularityWithUnity.Desktop.ModuleF.dll" moduleType="ModularityWithUnity.Desktop.ModuleF, ModularityWithUnity.Desktop.ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleF" startupLoaded="false">
            <dependencies>
                <dependency moduleName="ModuleE"/>
            </dependencies>
        </module>
    </modules>
</configuration>

即使程序集在全局程序集缓存中或与程序位于同一文件夹中,assemblyFile 属性也是必须的。

还需要覆盖 CreateModuleCatalog 方法:

protected override IModuleCatalog CreateModuleCatalog()
{
    return new ConfigurationModuleCatalog();
}
在目录中发现

Prism 允许将本地目录指定为 WPF 中的模块目录,然后自动扫描指定的文件夹并搜索程序集。要使用这种方法,需要在模块类上使用声明属性来指定模块名称和依赖。

protected override IModuleCatalog CreateModuleCatalog()
{
    return new DirectoryModuleCatalog() {ModulePath = @".\\Modules"};
}
[Module(ModuleName = "ModuleA", OnDemand = true)]
[ModuleDependency("ModuleD")]
public class ModuleA : IModule
{
}

模块间通信

下面是几种松耦合的通信模式,都有各自的优点,通常会结合使用。

  • 事件 - 模块可以订阅其他模块发布的事件来实现通信。但可能会难以维护,特别是要将许多事件编排在一起完成某个任务时。这时考虑共享服务。
  • 共享服务 - 通过公共接口访问的类。通常位于共享程序集并提供系统范围的服务,例如身份验证、日志记录或配置
  • 共享资源 - 比如数据库或一组 Web 服务
我的公众号 HelloPragram

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值