65.9K
CodeProject 正在变化。 阅读更多。
Home

Prism 4 应用程序清单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (50投票s)

2011年3月6日

CPOL

18分钟阅读

viewsIcon

178152

downloadIcon

7548

本文分步介绍了如何设置 Prism 应用程序。

引言

本文是作为《Prism 4 视图切换应用程序开发》的配套文章编写的,该文章也发布在 CodeProject 上。但是,它可以作为设置几乎任何 Prism 4 应用程序的指南。本文分步介绍了如何设置 Prism 应用程序。

本文中的清单假定开发人员将使用 Unity 2.0 作为应用程序的依赖注入 (DI) 容器,并且日志记录将使用 log4net 框架执行。但是,该清单并不严重依赖这些组件,并且应该很容易适用于其他 DI 容器和日志记录框架。

该清单包括设置 Prism 应用程序以进行视图切换所需的步骤,并且文章附带的演示应用程序是一个视图切换应用程序。有关视图切换的更多信息,请参阅配套文章。请注意,演示应用程序未实现日志记录。

第一步:创建 Prism 解决方案

设置 Prism 应用程序的第一步是创建和配置解决方案及 Shell 项目。

第一步 a – 创建解决方案:创建一个新的 WPF 项目,确保“新建项目”对话框中的“解决方案”下拉列表设置为“创建新解决方案”。“名称”字段应包含解决方案的名称。如果您要在应用程序中使用 WPF 功能区,请务必选择“WPF 功能区应用程序”作为项目类型,因为它的窗口与标准 WPF 窗口略有不同。

第一步 b – 将 DLL 添加到解决方案库:在解决方案的根级别创建一个名为 [解决方案名称].Library 的文件夹。在该文件夹中,创建一个名为 Prism 的子文件夹。将以下 DLL 添加到该文件夹

  • Microsoft.Practices.Prism.dll(及相应的 XML 文件)
  • Microsoft.Practices.Prism.UnityExtensions.dll(及相应的 XML 文件)
  • Microsoft.Practices.ServiceLocation.dll(及相应的 XML 文件)
  • Microsoft.Practices.Unity.dll(及相应的 XML 文件)

XML 文件为 DLL 文件提供 IntelliSense。

我们将 Prism DLL 复制到解决方案库文件夹,以便我们可以为解决方案使用 Prism 的私有或并排安装。这种方法消除了 Prism 更新时可能出现的一些版本问题。例如,我维护了几个 Prism 2.x 解决方案。由于每个解决方案都使用自己的 Prism DLL,因此旧版本不会干扰新版本,反之亦然。

第一步 c – 设置对库 DLL 的引用:在解决方案资源管理器“引用”部分,添加对前一步添加到解决方案库的 DLL 的引用。

第一步 d – 重命名 Shell 窗口:首先,在解决方案资源管理器中将 MainWindow.xaml 重命名为 ShellWindow.xaml。然后,在 VS 中打开 ShellWindow.xaml.cs。类名仍将为 MainWindow。使用 Visual Studio 重构工具重命名该类;这将更改对该类的所有引用。

第一步 e – 向 Shell 窗口添加命名空间定义:向 ShellWindow.xaml 添加 XAML 命名空间定义

xmlns:prism=”http://www.codeplex.com/prism”

第一步 f – 布局 Shell 窗口ShellWindow.xaml 将包含声明为区域的控件,通常是 ContentControlItemsControl 对象。这些控件中的每一个都代表 Shell 窗口中的一个区域。这些区域将包含加载到 Shell 窗口中的内容。

  • ContentControl 区域适用于一次显示一个视图的区域。
  • ItemsControl 区域适用于一次显示多个视图的区域,例如上面屏幕截图中的任务按钮。

ShellWindow.xaml 的布局方式与其他任何窗口一样,使用网格、分隔符和其他布局控件。唯一的区别是窗口几乎不包含实际控件。相反,它包含声明为区域的占位符控件。Prism 稍后会将区域的内容插入这些占位符。

每个区域控件都需要 x:NameRegionName。常规的 x:Name 用于您的代码,以便在需要时引用控件。Prism 的 RegionManager 使用 RegionName 来稍后加载内容。因此,基于 ItemsControl 的区域声明如下所示

<ItemsControl x:Name=”MyRegion” prism:RegionManager.RegionName=”MyRegion” />

请注意,这两个名称可以相同。

第一步 g – 创建 Bootstrapper:Bootstrapper 初始化 Prism 应用程序。大部分繁重的工作由 Prism 库完成,由开发人员创建的 Bootstrapper 类的主要任务是调用此功能。要设置 Bootstrapper,请先在 Shell 项目中创建一个名为 Bootstrapper.cs 的类。将类签名更新为继承自 UnityBootstrapper 类。

演示下载文件中包含一个示例 Bootstrapper 类。示例类包含下面讨论的方法重载。

第一步 h – 重写 CreateShell() 方法:创建一个 CreateShell() 方法的重载,使其如下所示

protected override System.Windows.DependencyObject CreateShell()
{
    /* The UnityBootstrapper base class will attach an instance 
     * of the RegionManager to the new ShellWindow. */

    return new ShellWindow ();
}

此重载创建了一个新的 ShellWindow 并将其设置为 Prism Shell。

第一步 i – 重写 InitializeShell() 方法:为 UnityBootstrapper 类创建 InitializeShell() 方法的重载。重载方法会将基类 Shell 属性设置为应用程序的 Shell 窗口。重载应如下所示

protected override void InitializeShell()
{
    base.InitializeShell();

    App.Current.MainWindow = (Window)this.Shell;
    App.Current.MainWindow.Show();
}

第一步 j – 重写 CreateModuleCatalog() 方法:此步骤假定您希望使用模块发现来填充模块目录,其中应用程序模块仅放置在指定文件夹中,Prism 将发现并加载它们。为 UnityBootstrapper 类创建 CreateModuleCatalog() 方法的重载。重载方法应如下所示

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

我们只需要指定编译时放置模块的文件夹。在此,我们在 Shell 项目 bin 文件夹中指定一个 Modules 子文件夹。

第一步 k – 重写 ConfigureRegionAdapterMappings() 方法:如果您的应用程序使用任何区域适配器,请为 UnityBootstrapper 类创建 ConfigureRegionAdapterMappings() 方法的重载。区域适配器用于将 Prism 区域功能扩展到无法开箱即用支持 Prism 区域的控件(如 WPF 功能区)。请参阅《Microsoft Prism 开发人员指南》的 附录 E

重载方法应如下所示

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
    // Call base method
    var mappings = base.ConfigureRegionAdapterMappings();
    if (mappings == null) return null;

    // Add custom mappings
    mappings.RegisterMapping(typeof(Ribbon), 
       ServiceLocator.Current.GetInstance<RibbonRegionAdapter>());

    // Set return value
    return mappings;
}

第一步 l – 修改 App 类App 类代表应用程序——它在应用程序启动时被调用。我们将使用 App 类来设置我们的 Prism 应用程序,通过配置我们的日志记录框架并调用我们在前面步骤中创建的 Bootstrapper。因此,请打开 App.xaml.cs,并向类添加以下重载方法

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    // Configure Log4Net
    XmlConfigurator.Configure();

    // Configure Bootstrapper
    var bootstrapper = new Bootstrapper();
    bootstrapper.Run();
}

日志记录器配置调用假定我们正在使用 log4net 框架,并且它正在 App.config 文件中配置。有关如何以这种方式配置 log4net 的更多信息,请参阅《如何配置 log4net》文档。

第一步 m – 修改 App.xaml:WPF 应用程序通常由 App.xaml 中的 StartupUri 属性初始化。此属性仅指向主窗口,作为启动时加载的窗口。由于我们在 App 类中控制初始化,因此我们不需要 XAML 属性。因此,请打开 App.xaml 并删除该属性。

第一步 n – 创建自定义日志记录器类:创建一个新的自定义日志记录器类,实现 ILoggerFacade,以允许 Prism 使用您的日志记录框架进行日志记录。一个示例自定义日志记录器作为 附录 B 附加到本文档。它使用 log4net 框架启用 Prism 日志记录。

第一步 o – 初始化自定义日志记录器:在应用程序 Bootstrapper 中,向 CreateLogger() 方法添加一个重载。重载只需创建并返回您的自定义日志记录器实例,如下所示

protected override Microsoft.Practices.Prism.Logging.ILoggerFacade CreateLogger()
{
    return new Log4NetLogger();
}

第二步:向应用程序添加模块

模块是 Prism 应用程序中的逻辑单元。每个模块都设置为 Prism 解决方案中的一个单独的类库 (DLL) 项目。示例模块初始化类的代码列表作为 附录 B 附加到本文档。

第二步 a – 创建模块:向您的解决方案添加一个 WPF 用户控件库项目。按照以下模式命名模块:[解决方案名称].Module[模块名称]。例如,如果解决方案名为 MySolution,并且模块代表文件夹导航器,则可以将其命名为 MySolution.ModuleFolderNavigator

第二步 b – 添加 Prism 引用:向您的新模块项目添加对以下 Prism 和 Unity 程序集的引用

  • Microsoft.Practices.Prism.dll
  • Microsoft.Practices.ServiceLocation.dll
  • Microsoft.Practices.Unity.dll
  • Microsoft.Practices.Prism.UnityExtensions.dll

需要 Microsoft.Practices.ServiceLocation 引用,因为它是 Prism 服务定位器使用的,用于从 DI 容器解析对象(参见本文 附录 A 中的 ConfigureRegionAdapterMappings())。

第二步 c – 重命名模块初始化器类:将新模块项目中的 Class1.cs 文件重命名为 [模块名称]。例如,如果模块项目名为 MySolution.ModuleFolderNavigator,则将 Class1 重命名为 ModuleFolderNavigator

第二步 d – 派生自 IModule 接口:更改模块初始化器类的类签名,使其派生自 IModule 接口。VS 将在接口名称下显示错误波浪线(因为它尚未实现),并将提供实现接口的选项。请 VS 执行此操作,它将添加实现 IModule 所需的 Initialize() 方法。暂时将 Initialize() 方法保持原样。

第二步 e – 向模块项目添加文件夹:向模块项目添加以下文件夹以帮助组织模块代码

  • Commands:包含本地视图模型使用的 ICommand 对象。
  • Services:包含由命令调用的本地服务。
  • ViewModels:模块视图的视图模型。
  • Views:模块的视图。

您可能使用所有这些文件夹,也可能不使用,具体取决于您的应用程序结构。例如,我使用 Commands 文件夹,因为我更喜欢将每个 ICommand 对象封装在单独的类中,而不是使用 Prism 的 DelegateCommand 对象。我发现这样做可以更好地分离代码,并使我的视图模型保持整洁。

第二步 f – 向每个模块添加生成后事件:由于 Prism 的全部目的是消除 Shell 及其模块之间的依赖关系,因此 VS 编译器将无法将应用程序模块识别为 Shell 项目的依赖项,这意味着模块不会被复制到 Shell 的应用程序输出文件夹。因此,每个模块都需要一个生成后事件命令来将模块复制到 Shell 项目应用程序输出文件夹中的 Modules 子文件夹。这是 Prism 将搜索应用程序模块的文件夹。

您可以在项目属性页的“生成事件”选项卡中访问生成后命令

事件的命令应如下所示

xcopy /y "$(TargetPath)" "$(SolutionDir)<ShellProjectName>\$(OutDir)Modules\"

其中 <ShellProjectName> = 解决方案名称(例如,“Prism4Demo.Shell”)。这是一个示例

xcopy /y "$(TargetPath)" "$(SolutionDir)Prism4Demo.Shell\$(OutDir)Modules\"

如果应用程序包含任何旨在保存其通用元素的项目(这些项目通常命名为 CommonInfrastructure 或类似名称),那么 Visual Studio 编译器很可能也无法检测到这些程序集,除非 Shell 引用了它们。如果 Visual Studio 编译器无法检测到这些项目,它将在应用程序尝试运行 Bootstrapper 时抛出异常,提示找不到这些项目。在这种情况下,您还需要为这些项目添加一个生成后命令。事件的命令应如下所示

xcopy /y "$(TargetPath)" "$(SolutionDir)<ShellProjectName>\$(OutDir)"

请注意,通用程序集被复制到 Shell 项目输出目录的根级别,而不是复制到 Modules 子文件夹。

许多桌面应用程序使用 SQL Compact 或其他进程内数据库作为数据存储。通常,数据库程序集会添加到项目中以进行私有部署。如果是这种情况,Visual Studio 编译器很可能也会错过数据库程序集,因为 Shell 项目对它们一无所知。因此,我们也需要为这些程序集设置生成后命令。我通常将命令放在我的 Common 项目中,或者如果我将持久化隔离在单独的项目中,则放在 Persistence 项目中。具体的命令将根据所使用的数据库技术而有所不同,并且某些数据库可能需要几个命令才能将程序集和支持 DLL 复制到 Shell 项目输出目录中的正确位置。这是我用来将所有必需的 SQL Compact 程序集从我的 Common 项目复制到 Shell 项目输出文件夹的命令

xcopy /s /y "$(SolutionDir)Library\SqlCompact\*.*" "$(SolutionDir)NoteMaster3\$(OutDir)"

我的解决方案根目录有一个库文件夹,其中包含应用程序所需的任何控件和其他程序集。SQL Compact 程序集位于 SqlCompact 子文件夹中。我同时复制 SQL Compact 的 32 位和 64 位版本,因此该命令会复制 SqlCompact 文件夹中的主程序集,以及 32 位和 64 位子文件夹及其内容。再次说明,我们将复制到输出根文件夹,而不是复制到 Modules 子文件夹。

最后,如果模块的视图使用任何第三方或自定义控件,则 VS 编译器出于与它无法检测模块和通用程序集相同的原因,可能无法将第三方控件检测为 Shell 的依赖项。因此,至少有一个使用每个第三方或自定义控件的模块将需要一个单独的生成后事件命令来将控件复制到 Shell 项目应用程序输出文件夹。这是一个示例

xcopy /y "$(TargetDir)FsTaskButton.dll" "$(SolutionDir)Prism4Demo.Shell\$(OutDir)"

请注意 $(TargetDir) 宏的使用,后跟要复制到 Shell 应用程序输出目录的 DLL 的名称。该宏将 VS 指向模块程序集的输出文件夹,其中将包含第三方控件,因为 VS 会将控件检测为模块的依赖项。毫不奇怪,我们将第三方控件复制到 Shell 项目输出文件夹的根级别。

最后,请注意关于生成后命令的以下几点

  • 命令必须包含在单行中。例如,如果在源路径和目标路径之间有换行符,命令将以错误退出。
  • 宏和命令的硬编码部分之间**不得有空格**。例如,$(SolutionDir) Prism4Demo.Shell\$(OutDir)Modules\ 将失败,因为 (SolutionDir)Prism4Demo.Shell\$(OutDir)Modules\ 之间有一个空格。
  • 宏包含它们自己的终止反斜杠,因此您不需要在宏和子文件夹之间添加反斜杠。
  • 将模块复制到 Modules 子文件夹时,如果子文件夹不存在,xcopy 会创建它。
  • /y 参数会抑制 Xcopy 命令的覆盖提示。如果省略此参数,Windows 将尝试在第一次编译后显示提示,这将导致 Visual Studio 中止命令并以代码 2 退出。

第三步:向模块添加视图

设置 Prism 应用程序的下一步是将视图添加到应用程序的模块中。应用程序 UI 由模块视图组成,Prism 将这些视图加载到 Shell 窗口区域中,这意味着每个视图都代表了整体 UI 的一部分。因此,Prism 视图通常包含在 WPF 用户控件中。

第三步 a – 创建视图:创建一个视图,通常采用 WPF 用户控件的形式。您无需对视图执行任何特殊操作即可使用 Prism。请注意,视图可能是多个控件的组合,例如 UI 表单,或者可能由单个控件组成,例如 Outlook 样式的任务按钮或应用程序功能区选项卡。在某些情况下,由单个控件组成的视图可能派生自控件,而不是派生自 UserControl。有关示例,请参阅演示应用程序模块中的功能区选项卡视图。

第三步 b – 注册视图:在模块的 Initialize() 方法中,使用 Prism Region Manager 或 Unity 容器注册视图。注册的选择取决于对视图期望的行为

  • 如果视图将在模块加载时加载,并且将在应用程序的生命周期内存在,则使用 Prism Region Manager 注册视图。此类视图的一个示例是 Outlook 样式的任务按钮。
  • 如果视图将根据用户在应用程序中的导航而加载和卸载,则使用 Unity 容器注册视图——稍后我们将使用 RequestNavigate() 来加载视图。此类视图的示例是 UI 表单或应用程序功能区选项卡。

模块初始化器类中的 Initialize() 方法应如下所示

#region IModule Members

/// <summary>
/// Initializes the module.
/// </summary>
public void Initialize()
{
    /* We register always-available controls with the Prism Region Manager, and on-demand 
     * controls with the DI container. On-demand controls will be loaded when we invoke
     * IRegionManager.RequestNavigate() to load the controls. */

    // Register task button with Prism Region
    var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
    regionManager.RegisterViewWithRegion("TaskButtonRegion", typeof(ModuleATaskButton));

    /* View objects have to be registered with Unity using the overload shown below. By
     * default, Unity resolves view objects as type System.Object, which this overload 
     * maps to the correct view type. See "Developer's Guide to Microsoft Prism" (Ver 4), 
     * p. 120. */

    // Register other view objects with DI Container (Unity)
    var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
    container.RegisterType<Object, ModuleARibbonTab>("ModuleARibbonTab");
    container.RegisterType<Object, ModuleANavigator>("ModuleANavigator");
    container.RegisterType<Object, ModuleAWorkspace>("ModuleAWorkspace");
}

#endregion

以下是 IRegionManager.RegisterViewWithRegion() 的方法参数

  • 区域名称:第一个参数指定将加载视图的区域名称。
  • 要注册的类型:第二个参数指定要加载到该区域的视图类型。Prism 负责实际加载视图。

以下是 IUnityContainer.RegisterType<TFrom, TTo>() 的参数

  • TFrom:第一个类型参数应始终为 System.Object,因为 Prism 最初将以此方式解析视图对象。
  • TTo:第二个类型参数应与视图对象的实际类型匹配。Unity 将把从 System.Object 解析的对象映射到此类型。
  • 视图名称:方法参数指定要注册的视图的名称,作为字符串值。

默认情况下,Prism 会在每次请求解析时创建一个新的视图对象实例。您可以覆盖此行为,并将类注册为单例,通过传递第二个方法参数,形式为新的 ContainerControlledLifetimeManager()

请注意,IUnityContainer.RegisterType() 还有其他重载,包括允许开发人员指定要解析的接口或基类,以及请求解析时要返回的具体类型的重载。

第三步 c – 实现 IRegionMemberLifetime 接口:如果视图应该在加载它的模块停用时卸载,则在视图或其视图模型上实现 IRegionMemberLifetime 接口。该接口包含一个属性 KeepAlive。将其设置为 false 将导致在用户导航到不同模块时卸载视图。以下是实现该接口的示例代码

using Microsoft.Practices.Prism.Regions;
using Microsoft.Windows.Controls.Ribbon;

namespace Prism4Demo.ModuleA.Views
{
    /// <summary>
    /// Interaction logic for ModuleARibbonTab.xaml
    /// </summary>
    public partial class ModuleARibbonTab : RibbonTab, IRegionMemberLifetime
    {
        #region Constructor

        public ModuleARibbonTab()
        {
            InitializeComponent();
        }

        #endregion

        #region IRegionMemberLifetime Members

        public bool KeepAlive
        {
            get { return false; }
        }

        #endregion
    }
}

如果 KeepAlive 始终为 false,则可以安全地在视图类上实现该接口并硬编码该值(如上所示)。但是,如果属性值将在运行时更改,请在相应的视图模型上实现该接口,以避免程序的后端直接与视图交互。

第三步 d – 添加 ViewSortHint 属性:如果视图将加载到 ItemsControl 区域或任何其他包含多个项目的区域,您可能需要向视图添加 ViewSortHint 属性。此属性指定视图加载到区域中的排序顺序。以下是一个 Outlook 样式的任务按钮示例

[ViewSortHint("01")]
public partial class ModuleATaskButton : UserControl
{
    public ModuleATaskButton()
    {
        InitializeComponent();
    }
}

请注意,声明为 Prism 区域的控件必须支持排序才能使 ViewSortHint 属性生效。

第四步:向应用程序添加通用项目

Prism 生产应用程序将有许多基类、接口、CompositePresentationEvent 类和资源字典。我们可以通过将所有这些应用程序资源放在一个项目中来集中依赖项并避免重复。模块包含对该项目的引用,这使它们能够直接调用基类和其他类,并使用“pack URL”访问资源字典。

Shell 项目可以作为这些应用程序范围内的资源的存储库。但是,这种方法会加紧模块与 Shell 之间的耦合,因为模块在没有 Shell 的情况下将无法进行测试。因此,我更喜欢将资源放在指定为解决方案“通用”项目的类库中。

我上面提到模块可以使用 pack URL 跨程序集边界访问资源字典。Pack URL 只是一个包含对用户计算机上其他程序集的引用的 URL,通常是同一解决方案中的另一个项目。它们看起来有些奇怪,但它们可以完成工作。我不会在这里花太多时间,因为它们在 MSDN 上有很好的文档记录。这是一个 pack URL 示例,它引用了 Prism 应用程序某个通用项目中的一个名为 Styles.xaml 的资源字典。该字典正在解决方案中另一个项目的应用程序级别被引用

<Application.Resources>
    <ResourceDictionary>
       <!-- Resource Dictionaries -->
       <ResourceDictionary.MergedDictionaries>
           <ResourceDictionary 
              Source="pack://application:,,,/Common;component/Dictionaries/Styles.xaml"/>
       </ResourceDictionary.MergedDictionaries>
   </ResourceDictionary>
</Application.Resources>

请注意,演示应用程序不使用资源字典,因此不包含此类引用。

我通常会向通用项目添加以下文件夹

  • BaseClasses
  • 接口
  • Events(用于 CompositePresentationEvent 类)
  • ResourceDictionaries

您可以使用通用项目作为业务模型和数据访问类的存储库,但我更喜欢将这些类放在单独的项目中。我发现这种方法更适合分离代码和管理应用程序各层之间的依赖关系。

结论

前面的步骤将生成 Prism 应用程序的基本框架。生产应用程序中有许多其他元素,例如应用程序模块中定义的每个视图的视图模型,以及实现应用程序用例的后端逻辑。您可以在上面引用的配套文章中找到有关演示应用程序的更多文档,以及关于模块之间松耦合通信的讨论。

一如既往,我欢迎其他 CodeProject 用户的同行评审。请在文章末尾的评论部分标记您发现的所有错误并添加任何建议。谢谢。

附录 A:示例 Bootstrapper 类

以下列表显示了演示应用程序中 Bootstrapper 类的代码

using System.Windows;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.UnityExtensions;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Windows.Controls.Ribbon;
using Prism4Demo.Shell.Views;
using PrismRibbonDemo;

namespace Prism4Demo.Shell
{
    public class Bootstrapper : UnityBootstrapper
    {
        #region Method Overrides

        /// <summary>
        /// Populates the Module Catalog.
        /// </summary>
        /// <returns>A new Module Catalog.</returns>
        /// <remarks>
        /// This method uses the Module Discovery method
        /// of populating the Module Catalog. It requires
        /// a post-build event in each module to place
        /// the module assembly in the module catalog
        /// directory.
        /// </remarks>
        protected override IModuleCatalog CreateModuleCatalog()
        {
            var moduleCatalog = new DirectoryModuleCatalog();
            moduleCatalog.ModulePath = @".\Modules";
            return moduleCatalog;
        }

        /// <summary>
        /// Configures the default region adapter
        /// mappings to use in the application, in order 
        /// to adapt UI controls defined in XAML
        /// to use a region and register it automatically.
        /// </summary>
        /// <returns>The RegionAdapterMappings instance
        /// containing all the mappings.</returns>
        protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
        {
            // Call base method
            var mappings = base.ConfigureRegionAdapterMappings();
            if (mappings == null) return null;

            // Add custom mappings
            var ribbonRegionAdapter = 
              ServiceLocator.Current.GetInstance<RibbonRegionAdapter>();
            mappings.RegisterMapping(typeof(Ribbon), ribbonRegionAdapter);

            // Set return value
            return mappings;
        }

        /// <summary>
        /// Instantiates the Shell window.
        /// </summary>
        /// <returns>A new ShellWindow window.</returns>
        protected override DependencyObject CreateShell()
        {
            /* This method sets the UnityBootstrapper.Shell property to the ShellWindow
             * we declared elsewhere in this project.
             * Note that the UnityBootstrapper base 
             * class will attach an instance 
             * of the RegionManager to the new Shell window. */

            return new ShellWindow();
        }

        /// <summary>
        /// Displays the Shell window to the user.
        /// </summary>
        protected override void InitializeShell()
        {
            base.InitializeShell();

            App.Current.MainWindow = (Window)this.Shell;
            App.Current.MainWindow.Show();
        }

        #endregion
    }
}

附录 B:示例模块类

以下列表显示了演示应用程序中 ModuleA 类的代码

using System;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Unity;
using Prism4Demo.ModuleA.Views;

namespace Prism4Demo.ModuleA
{
    /// <summary>
    /// Initializer class for Module A of the Prism 4 Demo.
    /// </summary>
    public class ModuleA : IModule
    {
        #region IModule Members

        /// <summary>
        /// Initializes the module.
        /// </summary>
        public void Initialize()
        {
            /* We register always-available controls 
             *  with the Prism Region Manager, and on-demand 
             * controls with the DI container.
             * On-demand controls will be loaded when we invoke
             * IRegionManager.RequestNavigate() to load the controls. */

            // Register task button with Prism Region
            var regionManager = 
                ServiceLocator.Current.GetInstance<IRegionManager>();
                regionManager.RegisterViewWithRegion("TaskButtonRegion", 
                              typeof(ModuleATaskButton));

            /* View objects have to be registered 
             *  with Unity using the overload shown below. By
             * default, Unity resolves view objects as 
             * type System.Object, which this overload 
             * maps to the correct view type. See "Developer's 
             * Guide to Microsoft Prism" (Ver 4), p. 120. */

            // Register other view objects with DI Container (Unity)
            var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
            container.RegisterType<Object, ModuleARibbonTab>("ModuleARibbonTab");
            container.RegisterType<Object, ModuleANavigator>("ModuleANavigator");
            container.RegisterType<Object, ModuleAWorkspace>("ModuleAWorkspace");
        }

        #endregion
    }
}

附录 C:示例自定义日志记录器类

以下列表显示了示例自定义日志记录器的代码

using log4net;
using Microsoft.Practices.Prism.Logging;

namespace FsNoteMaster3
{
    class Log4NetLogger : ILoggerFacade
    {
        #region Fields

        /* Note that the ILog interface and
         * the LogManager object are Log4Net members.
         * They are used to instantiate the Log4Net 
         * instance to which we will log. */

        // Member variables
        private readonly ILog m_Logger = 
                LogManager.GetLogger(typeof(Log4NetLogger)); 

        #endregion

        #region ILoggerFacade Members

        /// <summary>
        /// Writes a log message.
        /// </summary>
        /// <param name="message">The message to write.</param>
        /// <param name="category">The message category.</param>
        /// <param name="priority">Not used by Log4Net; pass Priority.None.</param>
        public void Log(string message, Category category, Priority priority)
        {
            switch (category)
            {
                case Category.Debug:
                    m_Logger.Debug(message);
                    break;
                case Category.Warn:
                    m_Logger.Warn(message);
                    break;
                case Category.Exception:
                    m_Logger.Error(message);
                    break;
                case Category.Info:
                    m_Logger.Info(message);
                    break;
            }
        }

        #endregion
    }
}
© . All rights reserved.