WPF Prism模块化开发

1、前言

  模块化开发是程序开发的一种方式,他将程序分为一组松散耦合的功能单元(命名模块),可集成到更大的应用程序中。模块封装了应用程序整体功能的一部分,通常代表一组相关功能。它可以包括一系列相关组件,如应用程序功能(包括用户界面和业务逻辑)或应用程序基础架构(如用于记录或验证用户的应用程序级服务)。模块是相互独立的,但可以松散地相互通信。使用模块化应用程序设计,您可以更轻松地开发、测试、部署和维护应用程序。

  例如,考虑个人银行申请。用户可以访问各种功能,例如在帐户之间转账、支付账单和从单个用户界面 (UI) 更新个人信息。但是在后台,这些功能都封装在一个离散模块中。这些模块相互通信,并与后端系统(如数据库服务器和 Web 服务)进行通信。应用程序服务集成每个不同模块中的不同组件,并处理与用户的通信。用户看到一个类似于单个应用程序的集成视图。

  下图显示了具有多个模块的模块化应用程序的设计。

模块组成

1.1 构建模块化应用的好处

  您可能已经在使用组件、接口和类构建精心设计的应用程序,并采用良好的面向对象设计原则。即便如此,除非非常小心,否则您的应用设计可能仍然是"单一的"(在应用程序内,所有功能都以紧密耦合的方式实现),这会使应用程序难以开发、测试、扩展和维护。

  另一方面,模块化应用方法可以帮助您识别应用程序的大型功能区域,并允许您独立开发和测试该功能。这可以使开发和测试更加容易,但也可以使您的应用程序更加灵活,并且更容易在未来扩展。模块化方法的好处是,它可以使您的整体应用架构更加灵活和可维护,因为它允许您将应用程序分解为可管理的部件。每一件都封装了特定的功能,并且每一件都通过清晰但松散耦合的通信通道进行集成。

1.2 Prism对模块化应用开发的支持

  Prism为模块化应用程序开发和应用程序内的运行时间模块管理提供支持。使用 Prism 的模块化开发功能可以节省您的时间,因为您不必实现和测试自己的模块化框架。Prism支持以下模块化应用程序开发功能:

  1. 用于注册命名模块和每个模块位置的模块目录;您可以通过以下方式创建模块目录
  2. 通过在代码或可扩展的应用程序标记语言 (XAML) 中定义模块
  3. 通过在目录中发现模块,您可以加载所有模块,而无需在集中目录中明确定义
  4. 通过在配置文件中定义模块
  5. 模块支持初始化模式和依赖性的声明性元数据属性
  6. 对于模块加载:
    • 依赖性管理,包括重复和循环检测,以确保模块按正确顺序加载,并且仅加载和初始化一次
    • 按需和背景下载模块,以尽量减少应用程序启动时间;其余模块可以在后台或需要时加载和初始化
  7. 与依赖性注射容器集成,以支持模块之间的松散耦合

1.3 核心概念,模块化应用的构建基块

  本节介绍了与Prism模块化相关的核心概念,包括接口、模块加载过程、模块目录、模块之间的通信和依赖性注入容器。IModule

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

  接口有两种方法,命名和.。两者都以依赖性注射容器为参数。当模块加载到应用程序中时,请首先调用该模块,并应用于注册模块实现的任何服务或功能。接下来称为方法。

using ClassLibrary1.Services;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary1
{
    public class MyModule : IModule
    {
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.Register<ClassLibrary1.Services.ISomeService, SomeService>();
        }
        public void OnInitialized(IContainerProvider containerProvider)
        {
            var regionManager = containerProvider.Resolve<IRegionManager>();
            regionManager.RegisterViewWithRegion("MyModuleView", typeof(Views.ThisModuleView));
        }
    }
}
2、模块生命周期

  Prism中的模块加载过程包括以下序列:

  • 注册模块是通过在类内实现 IModule 界面创建的。
  • 发现模块。特定应用程序在运行时间加载的模块在模块目录中定义。目录包含有关要加载的模块的信息,例如其位置以及要加载的模块的顺序。
  • 加载模块。包含模块的组件被加载到内存中。
  • 初始化模块。然后对模块进行初始化。这意味着创建模块类实例,并通过界面调用它们和方法。

 

2.1模块目录

 

  保存有关应用程序可以使用的模块的信息。目录本质上是库的集合。每个模块在记录模块名称、类型和位置等属性的类中进行描述。使用模块信息实例填充模块目录有几种典型的方法:ModuleInfo

    • 代码中的注册模块
    • 在 XAML 中注册模块
    • 在配置文件中注册模块
    • 在磁盘上的本地目录中发现模块

  您应该使用的注册和发现机制取决于您的应用程序需要什么。使用配置文件或 XAML 文件,您的应用程序无需引用模块。使用目录可以允许应用程序发现模块,而无需在文件中指定模块。

2.2 控制何时加载模块

Prism应用程序可以尽快初始化模块,称为"可用时",或当应用程序需要模块时,称为"按需"考虑以下加载模块指南:

  • 运行应用程序所需的模块必须加载应用程序,并在应用程序运行时进行初始化。
  • 可按需加载和初始化包含很少使用的功能(或可选其他模块所依赖的支持模块)的模块。

考虑您如何划分应用程序、常见使用方案和应用程序启动时间,以确定如何配置应用进行初始化。

2.3 将模块与应用程序集成

  每个组件和组件都提供一个基于类,用作应用类的基础类。覆盖虚拟方法以创建所需的模块目录类型。ApplicationCreateModuleCatalog

对于应用中的每个模块,实现界面以注册模块类型和服务。在将模块集成到应用中时,以下是需要做的常见事项:IModuleInfo

  • 将模块的视图添加到应用程序的导航结构中。使用视图发现或视图注入构建复合 UI 应用程序时,这种情况很常见。
  • 订阅应用级别的事件或服务。
  • 将共享服务与应用程序的依赖性注射容器进行注册。
2.4、模块之间的通信

  尽管模块之间的耦合度较低,但模块之间相互通信是很常见的。有几个松散耦合的通信模式,每个都有自己的优势。通常,这些模式的组合用于创建生成的解决方案。以下是以下一些模式:

  • 松散耦合的事件。模块可以广播发生某个事件。其他模块可以订阅这些事件,因此当事件发生时,将通知它们。松散耦合的事件是设置两个模块之间通信的轻量级方式:因此,它们很容易实现。然而,过于依赖事件的设计可能难以维护,特别是如果许多事件必须一起编排才能完成单个任务。在这种情况下,最好考虑共享服务。
  • 共享服务。共享服务是一个可以通过通用界面访问的类。通常,共享服务会在共享总成中找到,并提供全系统服务,如身份验证、记录或配置。
  • 共享资源。如果您不希望模块直接相互通信,您也可以让模块通过共享资源(如数据库或一组 Web 服务)进行间接通信。
2.5、依赖性注射和模块化应用

  UnityDryIoc等容器允许您轻松使用反转控制 (IoC) 和依赖性注射,这是强大的设计模式,有助于以松散耦合的方式组成组件。它允许组件获得对它们所依赖的其他组件的引用,而不必硬编码这些引用,从而促进更好的代码再利用和提高灵活性。当构建松散耦合的模块化应用程序时,依赖性注射非常有用。棱镜设计为对用于在应用程序中构成组件的依赖性注射容器不可知。

无论选择哪三个容器,Prism 都将使用容器构建和初始化每个模块,以便它们保持松散耦合。

2.6、关键决策

您将做出的第一个决定是您是否想要开发模块化解决方案。如前一节所述,构建模块化应用程序有许多好处,但您需要在时间和精力方面做出承诺才能获得这些好处。如果您决定开发模块化解决方案,还有几件事情需要考虑:

  • 确定您将使用的框架。您可以创建自己的模块化框架、使用棱镜或其他框架。
  • 确定如何组织您的解决方案。通过定义每个模块的边界,包括每个模块的组件是其中的一部分,接近模块化架构。您可以决定使用模块化来简化开发,并控制应用程序的部署方式,或者它是否支持插件或可扩展的架构。
  • 确定如何划分模块。模块可以根据要求进行不同的划分,例如,按功能区域、提供商模块、开发团队和部署要求划分。
  • 确定应用程序将为所有模块提供的核心服务。例如,核心服务可能是错误报告服务或身份验证和授权服务。
  • 如果您正在使用 Prism,请确定您正在使用什么方法在模块目录中注册模块。对于 WPF,您可以在代码、XAML、配置文件中注册模块,或在磁盘上的本地目录中发现模块。
  • 确定模块通信和依赖策略。模块需要相互通信,并且需要处理模块之间的依赖关系。
  • 确定您的依赖注射容器。通常,模块化系统需要依赖性注入、反转控制或服务定位器,以便允许松散的耦合和动态加载和创建模块。棱镜允许在使用 Unity 或 DryIoc 之间进行选择,并为基于 Unity 和 DryIoc 的应用程序提供库。
  • 尽量减少应用程序启动时间。考虑模块的点播和背景下载,以最大限度地缩短应用程序启动时间。
  • 确定部署要求。您需要考虑如何部署您的应用程序。

下一节提供了其中一些决定的细节。

2.7、将应用程序划分为模块

  当您以模块化的方式开发应用程序时,您将应用程序构建为可单独开发、测试和部署的单独客户端模块。每个模块将封装应用程序整体功能的一部分。您必须做出的第一个设计决策之一是决定如何将应用程序的功能划分为离散模块。

模块应封装一组相关问题,并具有一组不同的责任。模块可以表示应用程序的垂直切片或水平服务层。

垂直切片应用程序

围绕垂直切片组织模块的应用程序

水平分层应用程序

  围绕水平层组织模块的应用程序较大的应用程序可能有带有垂直切片和水平层的模块。模块的一些示例包括:

  • 包含特定应用功能的模块,例如提供新闻和/或公告的模块
  • 包含一组相关使用案例(如购买、开具开票或一般分类账)的特定子系统或功能的模块
  • 包含基础服务(如记录、缓存和授权服务或 Web 服务)的模块
  • 包含调用业务线 (LOB) 系统的服务的模块,如 Siebel CRM 和 SAP 以及其他内部系统

  模块对其他模块的依赖性应最小。当模块依赖于另一个模块时,应松散地耦合,使用共享库中定义的界面而不是具体类型,或者使用事件聚合器通过事件聚合器事件类型与其他模块进行通信。模块化的目标是对应用程序进行分区,使其即使在添加和删除功能和技术时仍保持灵活、可维护和稳定。实现此目的的最佳方式是设计您的应用程序,使模块尽可能独立,具有明确定义的界面,并尽可能隔离。

2.8、确定项目与模块的比例

  创建和包模块有几种方法。建议和最常见的方法是创建每个模块的单个总件。这有助于保持逻辑模块的独立性,并促进适当的封装。它还使将装配作为模块边界以及如何部署模块的包装更加容易。但是,没有什么能阻止单个组件包含多个模块,在某些情况下,最好将解决方案中的项目数量降至最低。对于大型应用程序,有 10 到 50 个模块并不罕见。将每个模块分离到自己的项目中会增加解决方案的复杂性,并会降低视觉工作室的性能。有时,如果您选择在每个装配/视觉工作室项目中坚持一个模块,则将模块或模块集分解为自己的解决方案来管理此是有意义的。

2.9、使用依赖性注射进行松散耦合

  模块可能取决于主机应用程序或其他模块提供的组件和服务。Prism 支持在模块之间注册依赖关系的能力,以便按正确的顺序加载和初始化它们。Prism还支持模块在加载到应用程序时初始化。在模块初始化期间,模块可以检索到所需的其他组件和服务的引用,并/或注册其包含的任何组件和服务,以便将其提供给其他模块。

  模块应使用独立的机制获取外部接口实例,而不是直接对混凝土类型进行刻例,例如使用依赖性注塑容器或工厂服务。依赖性注射容器(如 Unity 或 DryIoc)允许类型通过依赖性注射自动获取其需要的接口和类型的实例。Prism 与 Unity 和 DryIoc 集成,使模块能够轻松使用依赖性注射。

下图显示了在加载需要获取或注册组件和服务参考的模块时典型的操作顺序。

依赖性注射示例

在此示例中,总成定义了一个类(以及实现订单功能的其他视图和类)。装配组定义一个基于"应用程序启动和启动过程包含以下步骤:OrdersModuleOrdersRepositoryCustomerModuleCustomersViewModelOrdersRepository

  1. 源自模块初始化过程的类,模块装载机加载并初始化 。AppPrismApplicationOrdersModule
  2. 在初始化中,它注册了容器。OrdersModuleOrdersRepository
  3. 模块装载机然后加载 。模块加载的顺序可以通过模块元数据中的依赖性来指定。CustomersModule
  4. 通过容器解决它,构建了一个实例。该依赖于(通常基于其界面),并通过构造器或属性注入表示它。容器注入依赖性,在构造视图模型的基础上注册的类型。最终结果是这些类之间没有紧密耦合的界面参考。CustomersModuleCustomerViewModelCustomerViewModelOrdersRepositoryOrdersModuleCustomerViewModelOrderRepository

三、解决方案案例

  本节描述了您在应用程序中处理模块时遇到的常见场景。这些方案包括定义模块、注册和发现模块、装载模块、初始化模块、指定模块依赖性、按需加载模块、在后台下载远程模块以及检测模块何时已加载。您可以在代码、XAML 或应用程序配置文件中或通过扫描本地目录来注册和发现模块。

3.1 定义模块

  模块是功能和资源的逻辑集合,其包装方式可以单独开发、测试、部署和集成到应用程序中。每个模块都有一个中心类,负责初始化模块并将其功能集成到应用程序中。该类实现界面,如此处所示。IModule

using ClassLibrary1.Services;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary1
{
    public class MyModule : IModule
    {
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {

            containerRegistry.Register<ClassLibrary1.Services.ISomeService, SomeService>();
        }
        public void OnInitialized(IContainerProvider containerProvider)
        {

            var regionManager = containerProvider.Resolve<IRegionManager>();
            regionManager.RegisterViewWithRegion("MyModuleView", typeof(Views.ThisModuleView));
        }
    }
}
实施该模块实施的依赖性注射容器处理注册的所有服务.方法的实现方式将取决于应用的要求。在这里,您可以注册您的意见,并完成可能需要的任何其他模块级别初始化。OnInitialized

3.2、注册和发现模块

  应用程序可以加载的模块在模块目录中定义。Prism模块LoadModlu使用模块目录来确定哪些模块可用于加载到应用程序中、何时加载以及按哪个顺序加载它们。模块目录由实现界面的类表示。模块目录类由基础类在应用初始化过程中创建。棱镜提供模块目录的不同实现供您选择。您还可以通过调用方法或从中提取来填充来自其他数据源的模块目录,从而创建具有自定义行为的模块目录。

3.3 代码中的注册模块

  最基本的模块目录和默认值由该类提供。您可以使用此模块目录通过指定模块类类型对模块进行编程注册。您还可以按编程方式指定模块名称和初始化模式。要直接在类中注册模块,请在应用程序的派生类中调用该方法。覆盖以添加模块。示例显示在以下代码中。

  protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
  {
            Type moduleCType = typeof(ClassLibrary1.MyModule);
            moduleCatalog.AddModule(new ModuleInfo()
            {
                ModuleName = moduleCType.Name,
                ModuleType = moduleCType.AssemblyQualifiedName,
            });
            base.ConfigureModuleCatalog(moduleCatalog);
   }

  要指定代码中的依赖性,请使用Prism提供的声明属性。

[Module(ModuleName = "ModuleA")]
[ModuleDependency("ModuleD")]
public class ModuleA : IModule
{
    ...
}
要指定代码中的按需加载,请将属性添加到模块信息的新实例中。使用以下代码:InitializationMode
Type moduleCType = typeof(ModuleC);
ModuleCatalog.AddModule(new ModuleInfo()
{
    ModuleName = moduleCType.Name,
    ModuleType = moduleCType.AssemblyQualifiedName,
    InitializationMode = InitializationMode.OnDemand,
});
3.4 使用 XAML 文件注册模块

  您可以通过在 XAML 文件中指定模块目录来声明定义模块目录。XAML 文件指定创建的模块目录类类型以及要添加到该类别中的模块。通常,将 .xaml 文件添加为空壳项目的资源。模块目录由应用创建,并调用该方法。从技术角度来看,此方法与定义代码非常相似,因为 XAML 文件只是定义要加用的对象的层次结构。

  以下代码示例显示指定模块目录的 XAML 文件Modularity.xaml。

<--! 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>
从 XAML 文件创建目录的示例如下:
protected override IModuleCatalog CreateModuleCatalog()
{
    return ModuleCatalog.CreateFromXaml(new Uri("/MyProject;component/ModulesCatalog.xaml", UriKind.Relative));
}
要指定 XAML 中的依赖关系,请按照以下示例操作:
<-- ModulesCatalog.xaml -->
<Modularity:ModuleInfo Ref="file://ModuleE.dll" moduleName="ModuleE" moduleType="ModuleE.Module, ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Modularity:ModuleInfo Ref="file://ModuleF.dll" moduleName="ModuleF" moduleType="ModuleF.Module, ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <Modularity:ModuleInfo.DependsOn>
        <sys:String>ModuleE</sys:String>
    </Modularity:ModuleInfo.DependsOn>
</Modularity:ModuleInfo>
要指定模块的按需加载,请将属性添加到元素中。startupLoadedModularity:ModuleInfo
<Modularity:ModuleInfo Ref="file://ModuleE.dll" moduleName="ModuleE" moduleType="ModuleE.Module, ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" startupLoaded="false" />
3.5、使用配置文件注册模块App.config

  在 WPF 中,可以指定 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>
在应用程序的类中,您需要指定配置文件是您的源。要做到这一点,要覆盖该方法并返回类的实例。AppModuleCatalogCreateModuleCatalogConfigurationModuleCatalog
protected override IModuleCatalog CreateModuleCatalog()
{
    return new ConfigurationModuleCatalog();
}

要指定应用中的依赖性。配置文件:

<-- app.config -->
<modules>
    <module assemblyFile="ModuleE.dll" moduleType="ModuleE.Module, ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="moduleE" />
    <module assemblyFile="ModuleF.dll" moduleType="ModuleF.Module, ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="moduleF">
        <dependencies>
            <dependency moduleName="moduleE" />
        </dependencies>
    </module>
</modules>
要使用配置文件指定按需加载,应设置元素的属性。startupLoadedmodulefalse
<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" />

3.6 在目录中发现模块DirectoryModuleCatalog

  Prism允许您指定本地目录作为 WPF 中的模块目录。此模块目录将扫描指定的文件夹并搜索用于应用模块的组件。要使用此方法,您需要使用模块类上的声明属性来指定模块名称及其拥有的任何依赖性。以下代码示例显示通过在目录中发现组件来填充的模块目录。

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

要指定依赖性,请使用与使用代码相同的方法。

要按需或启动时处理加载,请更新属性如下:Module

[Module(ModuleName = "ModuleA", OnDemand = true)]
[ModuleDependency("ModuleD")]
public class ModuleA : IModule
{
    ...
}

3.7、请求按需加载模块

  模块指定为按需后,应用程序可以要求加载模块。想要启动装载的代码需要获得对在类中容器中注册的服务的引用。IModuleManagerApp,模块的明确负载可通过以下代码执行:

public class SomeViewModel : BindableBase
{
    private IModuleManager _moduleManager = null;

    public SomeViewModel(IModuleManager moduleManager)
    {
        // use dependency injection to get the module manager
        _moduleManager = moduleManager;
    }

    private void LoadSomeModule(string moduleName)
    {
        _moduleManager.LoadModule(moduleName);
    }
}
3.8、检测模块何时加载

  该服务为应用程序提供了一个事件,用于跟踪模块何时加载或无法加载。ModuleManager

public class SomeViewModel : BindableBase
{
    private IModuleManager _moduleManager = null;

    public SomeViewModel(IModuleManager moduleManager)
    {
        _moduleManager = moduleManager;
        _moduleManager.LoadModuleCompleted += _moduleManager_LoadModuleCompleted;
    }

    private void _moduleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
    {
        // ...
    }
}

  为了保持应用程序和模块松散耦合,应用程序应避免使用此事件将模块与应用程序集成。相反,模块的并且应该处理与应用程序的集成。RegisterTypesOnInitialized

包含属性。如果模块无法加载,应用程序想要防止记录错误和抛出一个例外,它可以设置此属性为真。

posted @ 2022-05-23 17:19  zyl2  阅读(95)  评论(0编辑  收藏  举报