📜 ⬆️ ⬇️

Prism Developer Guide - Part 4, Modular Application Development

Table of contents
  1. Introduction
  2. Initializing Prism Applications
  3. Manage dependencies between components
  4. Modular Application Development
  5. Implementation of the MVVM pattern
  6. Advanced MVVM scripts
  7. Creating user interface
    1. User Interface Design Recommendations
  8. Navigation
    1. View-Based Navigation (View-Based Navigation)
  9. The interaction between loosely coupled components

A modular application is such an application that can be divided into a number of functional blocks (modules) that can be integrated into one whole. The client module encapsulates part of the overall functionality of the application and is usually a set of interrelated functional parts. It may include a set of related components, such as application functions, including user interface and business logic, or parts of the application infrastructure, such as application-level services for logging, or authenticating and authorizing users. Modules are independent of each other, but can interact with each other in a weakly coupled way. Modular applications can facilitate the development, testing, deployment, and expansion of your application.

For example, consider a personal banking application. The user can access a variety of functions, such as transferring money between accounts, paying bills, and updating personal data using a single user interface (UI). However, each of these functions is encapsulated within a discrete module. These modules communicate with each other and with backend systems, such as database servers and web services. Application services integrate the various components within each of the various modules and handle user interaction. The user sees an integrated view that looks like a single seamless app.

The following illustration shows the modular application project.
')
Modular application

Benefits from creating modular applications


You are probably already creating a well-designed application using assemblies, interfaces, classes, and good object-oriented design principles. In this case, if you do not take serious measures, the design of your applications will remain "monolithic" (where all the functionality is implemented in a highly connected way within the application), this can lead to the application being difficult to develop, test, expand, and maintain.

A modular approach to building an application, on the other hand, can help highlight large-scale functional areas and develop or test them independently. This can make development and testing easier, and your application more flexible and easily expandable in the future. The advantage of the modular approach is that it can make the application architecture more flexible and maintainable by dividing the application into parts that are easy to manage. Each part encapsulates a specific functionality, and integrates through clear, but weakly connected channels.

Prism development support for modular applications


Prism helps you develop modular applications and manage modules at runtime. Using the functionality of Prism, you can save time, since you do not need to implement and test your own platform for building modular applications. Prism supports the following functions for developing modular applications:

Basic concepts


This section provides basic concepts related to the modularity of Prism, including the IModule , the module loading process, the module catalog, the communication between the modules, and the dependency injection containers.

IModule : modular application building block


A module is a logical set of functional components and resources collected in one place. Modules can be developed, tested, deployed, and integrated into the application separately. A package can include one or more assemblies, which can be located separately, or assembled in a single XAP file. Each module has a central class that is responsible for initializing and integrating the functionality of the module into the application. This class implements the IModule . The presence of a class that implements the IModule is enough to identify the package as a module. The IModule has a single Initialize method, within which you can implement any logic necessary to initialize and integrate the functionality of the module into the application. Depending on the purpose of the module, it can register views in the regions of the user interface, make additional services available to the application, or extend its functionality. The following code shows the minimal implementation of the module.

 public class MyModule : IModule { public void Initialize() { //    . } } 

The note
Instead of using the initialization mechanism provided by the IModule , Stock Trader RI uses a declarative, attribute-based approach to register views, services, and types.

Module lifetime


The process of loading a module into Prism includes the following:
  1. Registration / detection of modules. The modules that will be loaded at runtime for a specific application are defined in the modules directory. The catalog contains information about the loadable modules, their location, and the order in which they should be loaded.
  2. Loading modules. Assemblies that contain modules are loaded into memory. This phase may require loading the module from the network or from another remote location or local directory.
  3. Initialization of modules. Creating a module class and calling the Initialize method via the IModule .

The following illustration shows the module loading process.

Module loading process

Module Catalog


ModuleCatalog contains information about the modules that can be used by the application. A directory is essentially a collection of ModuleInfo classes. Each module is described by the ModuleInfo class, which stores the name, type, and location of the module. There are several typical approaches to filling ModuleCatalog with ModuleCatalog instances:

The choice of registration and detection mechanism to use depends on what the application needs. Using a configuration file or a XAML file allows an application not to store references to modules. Using a local directory may allow an application to detect modules without having to define them in any file.

Management of the module loading moment


Prism applications can initialize modules as soon as possible, what is known as “when available”, or when the application needs them, what is known as “on-demand”. For Silverlight applications, modules can be loaded with the application, or in the background after the application starts. Consider the following module loading instructions:

Consider how the application is divided, common use scenarios, application launch rate, and the number and size of downloads to determine how to configure the loading and initialization of modules.

Module integration with the application


Prism provides the following classes needed to load your application: UnityBootstrapper and MefBootstrapper . These classes can be used to create and configure a module manager, which is required to detect and load modules. You can override the module directory configuration method to register the modules defined in the XAML file, the configuration file, or specify the directory location.

Use the module Initialize method to integrate the module with the rest of the application. The way you do this will depend on the structure of the application and the content of the module. Below are the general steps you need to take to integrate the module into your application:

Communication between modules


Even considering that modules should be weakly connected, they tend to exchange data and messages with each other. There are several communication patterns for loosely coupled systems, each with its own advantages and disadvantages. As a rule, eventually, combinations of these patterns are used. The following are some of these patterns:

Dependency injection and modular applications


Containers such as the Unity Application Block (Unity) and the Managed Extensibility Framework (MEF) allow you to easily use Control Inversion (IoC) and dependency injection, which are powerful design patterns that help connect components in a loosely coupled way. This allows components to get references to other components on which they depend, without the need to hard code these links, thus obtaining code reuse and increased flexibility. Dependency injection is very useful when creating a loosely coupled modular application. Prism was designed to be independent of the DI container used to compose the components of an application. The choice of container is your business, and it will largely depend on the basic operational characteristics and preferences. There are two main dependency injection platforms for consideration from Microsoft - Unity and MEF.

Patterns & practices The Unity Application Block represents a full-featured dependency injection container. It supports property-based injection, constructor-based injection, and policy injection, which allows you to transparently introduce behaviors and policies between components. It also supports many other features typical of dependency injection containers.

MEF (which is now part of the .NET Framework 4 and Silverlight 4) allows you to create extensible applications, support dependency-based composition, and also provides other functions that support modular application development. This allows an application to detect components at runtime and then integrate them into the application. MEF provides excellent opportunities for expansion and composition. These include detecting assemblies and types, resolving dependencies, introducing dependencies, and some features for downloading assemblies and XAP files. Prism supports the use of MEF features such as:

Key decisions


The first decision you have to make is whether you want to develop a modular application. There are numerous advantages to creating modular applications, as discussed in the previous section, but there is also additional time and effort that you must make to get these benefits. If you still decide to develop a modular application, then there are a few things to consider:

The following sections examine these decisions in detail.

Dividing an application into modules


When you develop your application in a modular way, you structure it into separate client modules that can be individually developed, tested, and deployed. Each module will encapsulate part of the full functionality of your application. One of the first design decisions that needs to be made is to decide how to divide the functionality of your application into discrete modules.

A module must encapsulate a number of related functionality and have a set of different responsibilities. A module can represent a vertical section of an application or a horizontal layer of services. Large applications are likely to have both types of modules.

,

,

A large application can have modules organized both in vertical sections and in horizontal layers. For example, modules may include the following:

A module should have a minimum set of dependencies on other modules. When a module has a dependency on another module, it must be loosely associated with it through the interfaces defined in the shared library, not through specific types, or, using EventAggregator , to communicate with other modules through events.

The goal of the modular principle is to divide the application in such a way that it becomes flexible, maintainable, and sustainable, even when functions and technologies are added and removed. The best way to achieve this is to develop your application so that the modules are as independent as possible, have well-defined interfaces, and are as isolated as possible.

Determining the ratio of projects and modules

There are several ways to create and package modules. The recommended and most common way is to create a single assembly per module. It helps to separate modules logically and promotes proper encapsulation. It also allows you to talk about the assembly as a module and vice versa. However, nothing prevents a single assembly from containing multiple modules, in some cases it may be preferable to minimize the number of projects in your solution. A large application may well have 10-50 modules. Moving each module to your own project adds complexity to the solution and can slow down Visual Studio performance. Sometimes it makes sense to divide a module or a set of modules into your own solutions if you want to stick with one module per project or assembly.

XAP and factoring module

For Silverlight applications, modules are usually packaged in separate XAP files, although in some cases, you may have more than one module per XAP. Consider how many XAP files you need to minimize the number and size of download requests required to run an application and activate a new option. If you want to split each module into its own project / assembly, you must decide whether to insert each assembly into its own XAP for deployment or include several assemblies in a single XAP.

Some factors affecting your choice of whether to include several modules in a single XAP file or to separate them:

To avoid loading the same builds several times in each XAP, there are two approaches that can be used:

Use dependency injection to achieve loose coupling.


A module may depend on components and services provided by the host application or other modules. Prism supports the ability to register dependencies between modules so that they are loaded and initialized in the correct order. Prism also supports initialization of modules after they are loaded. During initialization, a module can get links to additional components and services that it needs, and / or register any components and services it contains to make them available to other modules.

A module must use an independent mechanism to get instances of external interfaces instead of directly creating specific types. It can do this through a dependency injection container or factory services. Dependency injection containers, such as Unity or MEF, allow a type to automatically obtain interface instances through dependency injection. Prism integrates with both Unity and MEF to allow modules to easily use dependency injection.
The following diagram shows a typical sequence of operations when loading modules that are required to get or register links to components and services.

.

In this example, the assembly OrdersModuledefines a classOrdersRepository(along with other views and classes that implement the functionality of the order). The assembly CustomerModuledefines a class CustomersViewModelthat depends on the class OrdersRepositorybased on the interface provided by the service. The launch of the application and the download process include the following steps:
  1. Bootstrapper starts the module initialization process, and the module loader loads and initializes OrdersModule.
  2. In the initialization stage OrdersModule, it registers OrdersRepositoryin a container.
  3. Loader module loads CustomersModule. The order of loading modules can be determined based on their metadata.
  4. CustomersModule CustomerViewModel , . CustomerViewModel OrdersRepository ( ) . , , OrdersModule . CustomerViewModel OrderRepository .


, , OrderRespository ( IOrderRepository ), , , , . , CustomersModule OrdersModule .

Notice that both modules have an implicit dependency on the dependency injection container. This dependency is introduced during the creation of the module in the loader.

Basic scripts


This section describes common scenarios that you encounter when working with modules in your application. These scenarios include defining a module, registering and discovering modules, loading modules, initializing modules, determining module dependencies, loading modules on demand, loading remote modules in the background, and determining the status of the loading process. You can register modules in code, in XAML, in the application's configuration file, or by scanning the local directory.

Module definition


A module is a logical set of functionality and resources that can be separately developed, tested, deployed, and integrated into an application. Each module has a central class that is responsible for initializing the module and integrating its functionality into the application. This class implements the interface IModuleas shown below.

 public class MyModule : IModule { public void Initialize() { //  . } } 

Note
Module names must be unique within the entire application.

The way in which you implement the method Initializewill depend on the requirements of your application. The class type of the module, the initialization mode, and any dependencies of the module are specified in the module directory. For each module in the directory, the loader creates an instance of the module class and then calls the method Initialize. Modules are processed in the order defined in the modules directory. The order of initialization at run time depends on when the modules are loaded, become available, and their dependencies are satisfied.

Depending on the type of module directory that your application uses, module dependencies can be set either by declarative attributes directly in the module class, or within the module directory file. The following sections will provide more detailed information.

Registration and detection of modules


The modules that an application can load are defined in the modules directory. Module Loader Prism uses the module directory to determine which modules are available for download, when to load them, and in what order they should be loaded.

The module directory is a class that implements the interface IModuleCatalog. The module catalog class is created by the loader class during application initialization. Prism provides various implementations of a catalog of modules from which you can choose the one you need. You can also populate a catalog of modules from another data source by calling a method AddModuleor inheriting a class from ModuleCatalogto create a catalog of modules with specialized behavior.

, Prism Common Service Locator, , . , , , , , . - .


The most basic module directory is provided by the class ModuleCatalog. You can use this directory to register modules in code by specifying the class type of the module. You can also specify the initialization mode and the module name. To register a module directly in a class ModuleCatalog, call a method AddModulein the class of Bootstrapperyour application.

 protected override void ConfigureModuleCatalog() { Type moduleCType = typeof(ModuleC); ModuleCatalog.AddModule( new ModuleInfo() { ModuleName = moduleCType.Name, ModuleType = moduleCType.AssemblyQualifiedName, }); } 

In the previous example, modules are directly referenced by the shell, thus the types of classes of modules that can be used in the method call are defined AddModule. That is why this example uses typeof(Module)to add modules to a directory.
Note
If the application has a direct link to the module type, you can add this type, as shown above. Otherwise, you must provide the fully qualified type name and location of the assembly.

To see another example of the determination module catalog in the code refer StockTraderRIBootstrapper.csto the Stock Trader the RI .
Note
The base class Bootstrapperprovides a method CreateModuleCatalogto assist in the creation ModuleCatalog. By default, this method creates an instance ModuleCatalog, but this method can be overridden in a derived class to create other types of module catalog.

Registering Modules Using the XAML File

You can define a catalog of modules declaratively in a XAML file. The XAML file determines which module directory class to create and which modules to add to it. Usually the .xamlfile is added as a resource to your shell project. The catalog of modules is created in the loader by a method call CreateFromXaml. From a technical point of view, this approach is similar to the definition ModuleCatalogin code, because the XAML file simply defines a hierarchy of objects to be instantiated.

The following code example shows a XAML file that defines a directory of modules.

 <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="ModuleB.xap" InitializationMode="WhenAvailable"> <Modularity:ModuleInfo ModuleName="ModuleB" ModuleType="ModuleB.ModuleB, ModuleB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </Modularity:ModuleInfoGroup> <Modularity:ModuleInfoGroup InitializationMode="OnDemand"> <Modularity:ModuleInfo Ref="ModuleE.xap" ModuleName="ModuleE" ModuleType="ModuleE.ModuleE, ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Modularity:ModuleInfo Ref="ModuleF.xap" ModuleName="ModuleF" ModuleType="ModuleF.ModuleF, 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> <!--      --> <Modularity:ModuleInfo Ref="ModuleD.xap" ModuleName="ModuleD" ModuleType="ModuleD.ModuleD, ModuleD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </Modularity:ModuleCatalog> 

Notes
ModuleInfoGroups provide a convenient way to group modules that are in the same .xap file or assembly, initialized in the same way, or have dependencies only on modules in the same group. The dependencies between the modules can be defined within the modules ModuleInfoGroup, however, it is not possible to specify the dependencies between the modules in different ModuleInfoGroups. Placing modules into groups of modules is optional. The properties that are set for the group will be applied to all modules in it. Note that modules can also be registered without being in a group.

In the class, Bootstrapperyou must indicate that the XAML file is the source for ModuleCatalog, as shown below.

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

Registration of modules using the configuration file

In WPF, it is possible to specify information about a module in a file App.config. The advantage of this approach is that this file is not compiled into the application. This makes it easy to add or remove modules at runtime, without recompiling the application.

The following code shows the configuration file that defines the module directory. If you want the module to automatically load, install startupLoaded="true".

  <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> 

Note
Even if your assemblies are in the global assembly cache or in the same folder as the application, an attribute is required assemblyFile. The attribute is used to map moduleTypeto the correct IModuleTypeLoaderone to be used.

In the Bootstrapperapplication class , you must specify that the configuration file is the source for ModuleCatalog. To do this, use the class ConfigurationModuleCatalogas shown in the following code.

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

Note
You can still add modules to ConfigurationModuleCatalogin the code. You can use this, for example, in order to make sure that the modules absolutely necessary for the operation of your application are added to the module directory.

Note
Silverlight does not support configuration files. If you want to use this approach for configuration in Silverlight, it is recommended to create your own ModuleCatalog, which reads the configuration of modules from the web service on the server.

Locate modules in the local directory

The class DirectoryModuleCatalogallows you to specify a local directory as a module directory in WPF. This module directory will scan the specified folder, and look for assemblies that provide modules for your application. To use this approach, you will need to use declarative attributes on your module classes to determine the module names and any dependencies they have. The following code example shows a directory of modules that is populated by detecting assemblies in a local directory.

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

Note
This functionality is not supported in Silverlight, because the Silverlight security model does not allow you to load assemblies from the file system.

Module loading


Once ModuleCatalogfull, the modules are ready for loading and initialization. Loading a module means that the module assembly is loaded from disk into memory. If the assembly is not on disk, you may need to first get it from another source. An example of this is downloading an assembly from the Internet using Silverlight .xapfiles. ModuleManagerresponsible for coordinating the initialization and loading process.

Module initialization


After loading the modules, they are initialized. This means that an instance of the module class is created and its method is Initializecalled. Initialization is where the module is integrated into the application. Consider the following options when initializing a module:


Determination of module dependencies


Modules may depend on other modules. If Module A depends on the Module B , the Module B must be initialized before Module A . ModuleManagerkeeps track of these dependencies and initializes the modules in the correct order. Depending on how you defined your module catalog, you can define your module dependencies in code, configuration, or XAML.

Determining code dependencies

For WPF applications that register modules in code or find them in a folder, Prism provides declarative attributes for the module class, as shown in the following example.

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

Determination of dependencies in XAML

The following XAML shows that the Module F depends on the Module E .

 <Modularity:ModuleInfo Ref="ModuleF.xap" ModuleName="ModuleF" ModuleType="ModuleF.ModuleF, ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" > <Modularity:ModuleInfo.DependsOn> <sys:String>ModuleE</sys:String> </Modularity:ModuleInfo.DependsOn> </Modularity:ModuleInfo> 

Determination of dependencies in the configuration file

The following example shows App.config file that Module D depends Module B .

 <modules> <module assemblyFile="Modules/ModuleD.dll" moduleType="ModuleD.ModuleD, ModuleD" moduleName="ModuleD"> <dependencies> <dependency moduleName="ModuleB"/> </dependencies> </module> 

Loading modules on demand


To load modules on demand, you must specify that they should be loaded into the module directory with the parameter set InitializationModeto OnDemand. After that, you must add code to your application requesting module loading.

Load on demand job in code

The definition that the module should be loaded on demand through attributes is shown in the following example.

 protected override void ConfigureModuleCatalog() { Type moduleCType = typeof(ModuleC); this.ModuleCatalog.AddModule(new ModuleInfo() { ModuleName = moduleCType.Name, ModuleType = moduleCType.AssemblyQualifiedName, InitializationMode = InitializationMode.OnDemand }); } 

XAML load on demand job

You can determine InitializationMode.OnDemandwhen you specify a module directory in XAML, as shown in the following code example.

 ... <Modularity:ModuleInfoGroup InitializationMode="OnDemand"> <Modularity:ModuleInfo Ref="ModuleE.xap" ModuleName="ModuleE" ModuleType="ModuleE.ModuleE, ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> ... 

Set load on demand in the configuration file

You can specify InitializationMode.OnDemandwhen specifying a directory of modules in a file App.config, as shown in the following code example.

 ... <module assemblyFile="Modules/ModuleC.dll" moduleType="ModuleC.ModuleC, ModuleC" moduleName="ModuleC" startupLoaded="false"/> .... 

Module load request

After the module is defined as loadable on demand, the application may request that it be loaded. The code that wants to initiate the download is required to obtain a link to the service IModuleManagerregistered in the container by the loader.

 private void OnLoadModuleCClick(object sender, RoutedEventArgs e) { moduleManager.LoadModule("ModuleC"); } 

Remote module loading in the background


Loading modules in the background after the application is launched, or only when the user needs them, can reduce the application launch time.

Preparing the module for remote download

In Silverlight applications, modules are packaged into .xapfiles. To load the module separately from the application, create a separate .xapfile. You may want to put several modules in a single .xapfile in order to optimize the number of load requests for replacing the size of each .xap file.
Note
For each .xap file, you will need to create a new Silverlight application project. In Visual Studio 2008 and 2010, only application projects produce separate .xapfiles. You will not need App.xamlor files MainPage.xamlin these projects.

Tracking the boot process

The class ModuleManagerprovides an event to track the progress of loading modules. It provides loaded bytes versus full load size for percent promotion. You can use it to display visual indicators of the download progress.

 this.moduleManager.ModuleDownloadProgressChanged += this.ModuleManager_ModuleDownloadProgressChanged; 

 void ModuleManager_ModuleDownloadProgressChanged(object sender, ModuleDownloadProgressChangedEventArgs e) { ... } 

Determining if a module has been loaded


The service ModuleManagerprovides an event to track when a module is loaded or not able to load.

 this.moduleManager.LoadModuleCompleted += this.ModuleManager_LoadModuleCompleted; 

 void ModuleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e) { ... } 

To keep the application and modules loosely coupled, you should avoid using this event to integrate the module with the application. Use the module method instead Initialize.

LoadModuleCompletedEventArgscontains a property IsErrorHandled. If the module fails to load, and the application wants to prevent it from ModuleManagerregistering an error and throwing an exception, you must set this property to true.
Note
After the module is loaded and initialized, the module assembly cannot be unloaded. The module instance reference will not be saved by Prism libraries, so an instance of the module class can be garbage collected after initialization has been completed.

Modules in MEF


This section only highlights the differences when using MEF as a dependency injection container.
Note
When using MEF, MefBootstrapperuses MefModuleManager. It extends ModuleManagerand implements the interface IPartImportsSatisfiedNotificationto ensure that it is ModuleCatalogupdated when new types are imported by MEF.

Registering Modules in Code Using MEF

When using MEF, you can apply an attribute ModuleExportto module classes so that MEF can automatically detect them.

 [ModuleExport(typeof(ModuleB))] public class ModuleB : IModule { ... } 

You can also use MEF to locate and load modules using a class AssemblyCatalogthat can be used to locate all exported module classes in an assembly, and a class AggregateCatalogthat allows multiple directories to be combined into one logical directory. By default, the class MefBootstrappercreates an instance AggregateCatalog. You can override the method ConfigureAggregateCatalogto register assemblies.

 protected override void ConfigureAggregateCatalog() { base.ConfigureAggregateCatalog(); // Module A        . this.AggregateCatalog.Catalogs.Add( new AssemblyCatalog(typeof(ModuleA).Assembly)); this.AggregateCatalog.Catalogs.Add( new AssemblyCatalog(typeof(ModuleC).Assembly)); } 

The Prism implementation MefModuleManagersynchronizes AggregateCatalogMEF and Prism ModuleCatalog, thus allowing Prism to detect modules added through ModuleCatalogor AggregateCatalog.
Note
MEF is widely usedLazy, Value .
Locate modules in a local directory using MEF

MEF provides a class DirectoryCatalogthat can be used to view a folder for assemblies containing modules (and other MEF types exported). In this case, you override the method ConfigureAggregateCatalogto register the directory. This approach is only available in WPF.

To use this approach, you must first define the module names and their dependencies using an attribute ModuleExport, as shown in the following example.

 protected override void ConfigureAggregateCatalog() { base.ConfigureAggregateCatalog(); DirectoryCatalog catalog = new DirectoryCatalog("DirectoryModules"); this.AggregateCatalog.Catalogs.Add(catalog); } 

Defining code dependencies using MEF

WPF, ModuleExport , .

 [ModuleExport(typeof(ModuleA), DependsOnModuleNames = new string[] { "ModuleD" })] public class ModuleA : IModule { ... } 

MEF , . MEF ModuleCatalog , , ModuleCatalog , XAML ( - ). ModuleCatalog MEF, ModuleCatalog , DependsOnModuleNames . MEF ModuleCatalog Silverlight, XAP.

MEF

MEF ModuleExport , , InitializationMode , , , .

 [ModuleExport(typeof(ModuleC), InitializationMode = InitializationMode.OnDemand)] public class ModuleC : IModule { ... } 

MEF

, Prism, MEF, MEF DeploymentCatalog , .xap .xap . MefXapModuleTypeLoader DeploymentCatalog AggregateCatalog .

.xap , . , , . Microsoft.Practices.Prism.MefExtensions.dll .

, DLL 'Copy Local'=false . .xap . .xap . , , , .xap , , .xap .

Additional Information


For more information about assembly caching, see "How to: Use Assembly Library Caching" on MSDN: http://msdn.microsoft.com/en-us/library/dd833069 ( VS.95 ) .aspx

To learn more about modular principle in Prism, see Modularity with MEF for WPF QuickStart or Modularity with Unity for WPF QuickStart. To learn more about QuickStarts, see Modularity QuickStarts for WPF .

For information about the Prism library functions used in building modular applications, see " Modules " in " Extending Prism ."

Source: https://habr.com/ru/post/176863/


All Articles