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

如何嵌入一个应用程序到停靠库

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2011年9月3日

CPOL

7分钟阅读

viewsIcon

29908

downloadIcon

2513

逐步将一个应用程序转换为停靠应用程序组件

Introduction

摘要

AvalonDock 是最流行的 WPF 开源停靠库。 Sofa 对其进行了封装,增加了功能,并允许 AvalonDock 轻松集成到 Prism 等多种不同架构中。

为了从停靠系统和多实例功能中获益,必须将现有应用程序转换为可托管在停靠容器中的组件。

使用 Sofa 可以快速轻松地完成此操作:本文档将逐步介绍此转换过程。

本文术语表

Sofa.Container.SofaContainer Sofa.Commons.SofaComponents Sofa 的主要类。

SofaContainer 类被插入到 WPF 窗口或 UserControl 中。管理此窗口或 UserControl 的应用程序在此文档中称为容器

SofaComponent 类嵌入了用户的应用程序。此应用程序在此文档中称为组件

示例:在以下示例中,我们将重用 CSWPFMasterDetailBinding 应用程序。我们将其转换为库,并使其成为组件。它将在 SofaBasiContainer 应用程序中运行,该应用程序是一个容器

1. 从应用程序到组件

Step 1

该应用程序由 2 个项目组成

第 1 个项目:容器: SofaBasicContainer

容器基本上只需要“包含”功能。我们使用的 SofaBasiContainer 容器在许多示例中都可以找到,并且被重用,只需稍作修改:只需调整 MEF 导入声明即可。

  • BaseWindow.xaml.cs 中的 MEF [ImportMany] 键设置为 Sofa.Examples. SofaComponization.SofaBasicContainer_ViewContract

第 2 个项目:组件: CSWPFMasterDetailBinding

在此步骤中,应用程序被转换为组件,并准备在之前的 SofaBasicContainer 容器中注册。

该应用程序是 CSWPFMasterDetailBinding。它来自 All-In-One Code Framework (WPF) 项目(http://1code.codeplex.com)。

  1. 将应用程序转换为库
    • 项目属性
      • 输出类型从 Windows 应用程序更改为类库。
      • SofaBasicContainer 为了使用 MEF,必须能够访问此项目的库:必须将生成输出路径设置为..\SofaBasicContainer\bin\Debug\AddIns\
      • 目标框架设置为 .NET 4
    • 删除 App.xamlApp.xaml.cs。在某些情况下,现有代码必须移至容器组件Usercontrol ,但此处没有。
    • MainWindow.xaml<Window x : Class ="CSWPFMasterDetailBinding.MainWindow" 已更改为<UserControl x : Class... xamlxaml.cs文件中,必须对某些标签(资源、触发器)、属性(Title、事件...)和部分类定义进行相应的调整。
  2. 为了成为组件,库必须能够注册到容器。这是使用 MEF 完成的。在 MainWindow.xaml.cs 中添加了 [Export] 声明和元数据。
    • 必须添加对 System.ComponentModel.Composition.Codeplex DLL 的引用才能使用 MEF。还需要引用 Sofa 库。
    • MEF [Export] 声明始终相同,可以从任何示例中复制。在此步骤中,唯一重要的要编辑的数据是
      • 需要调整 [Export] 键以匹配容器[ImportMany] 声明中使用的“Sofa.Examples. SofaComponization.SofaBasicContainer_ViewContract”键。
      • ProductName (即 SofaComponent id)设置为“CSWPFMasterDetailBinding”,并设置 Label

就是这样。您可以运行 SofaBasicContainer 容器,并在其菜单中找到 CSWPFMasterDetailBinding 组件。加载一个或多个,停靠,取消停靠,调整窗口大小……

当前结果:原始应用程序现在在容器中运行,并且是多实例应用程序。

但其 GUI 没有改变……

2. 从简单组件到子组件

此步骤的目标是将之前的组件拆分为 2 个组件,每个组件包含之前组件中的一个列表。

这两个组件可以由 SofaBasicContainer 托管,但它们总是协同工作,因此最好将它们托管在一个新容器中,而这个容器本身也是一个组件,托管在 SofaBasicContainer 容器中。

“1. 原始应用程序到 SofaComponent”文件夹被复制并重命名为“2. 简单 SofaComponent 到子 SofaComponents”。

第 1 个项目:容器: SofaBasicContainer

SofaBasicContainer 项目是一个标准的容器,不需要任何修改。

第 2 个项目:组件和容器:CSWPFMasterDetailBinding

  1. 原始组件被复制。
    • MainWindow.xaml 类被复制。文件和类被重命名:一个重命名为“CustomerListComponent”,另一个重命名为“OrderListComponent”。
    • CustomerListComponent 中仅保留 Customer 列表(listViewCustomers ),在 OrderListComponent 中保留 Order 列表(listViewOrders )。<UserControl.Resources> 标签与 CustomerList 相关,并从 OrderList 中删除。
    • 组件的 MEF 导出目标已更改为下一步将创建的容器。
      • Sofa.Examples.SofaComponization. SofaBasicContainer_ViewContract 已重命名为 Sofa.Examples.SofaComponization. MainComponent_ViewContract
      • ProductName 已从 CSWPFMasterDetailBinding 重命名为 CustomerList OrderList ,并编辑了 Labels
  2. 新的组件-容器

    由于我们希望这两个组件在一个窗口中打开,因此我们需要一个新容器。这个容器也将是一个组件,托管在初始 SofaBasicContainer 中,取代之前的 MainWindow 组件

    这个容器-组件是一个名为 MainComponent 的新类。它是 SofaBasicContainer (用于容器代码)和之前的 MainWindow 类(用于组件代码)的混合体。

    组件 (Component)

    • 组件的唯一代码是 MEF [Export] 声明。键设置为与 SofaBasicContainer [ImportMany] 声明相同的值。

    容器

    • 当前项目托管一个容器:必须添加对 Sofa 库的引用。
    • 该类实现 IBaseContainer 接口,并且必须具有 public SofaContainer SofaContainer(已使用)和 public SofaMenu SofaMenu (未使用)声明。
    • 该类将导入之前的两个“CustomerListComponent”和“OrderListComponent组件。其 [ImportMany] 声明设置为与组件[Export] 键相同的值。它实现 IPartImportsSatisfiedNotification 接口,以便触发 OnImportsSatisfied 方法。SofaBasicContainer Compose 方法必须运行一次,并且在此子容器中不存在。
    • 组件-容器的“子组件”在容器完全初始化之前无法打开。唯一有效的时间是在 SofaCommonEventHandler 方法中处理“PostOpenSofaCommonEvent 时。使用了 sofaContainer.OpenComponent("CustomerList")sofaContainer.OpenComponent("OrderList") 方法。组件名称是硬编码的,这不优雅但不是最终的(参见 3. 绑定两个列表)。

    您可以运行应用程序,这两个子组件将打开在 MainComponent 中,而 MainComponent 又打开在 SofaBasicContainer 中。

    但是 OrderListComponent 没有绑定源,也没有显示所选客户的订单。

  3. 绑定两个列表

    所有操作都在 MainComponent PostOpen 事件处理代码中完成:使用 Sofacontainer SofaComponentList 访问这两个组件,并将 CustomerListComponent listViewCustomers 用作 OrderListComponent DataContext

现在应用程序可以正常工作了。

3. 关于视图...

第 1 个项目:容器: SofaBasicContainer

此项目实现了一个完整的视图管理场景:主要功能包括在打开/关闭容器时加载/保存上次使用的视图,以及一个允许创建、加载和删除视图的菜单。

实现此目标所需的步骤如下:

  • 资源:导入 PerspectiveManager 助手及其关联的 PerspectiveName ,并调整命名空间。
  • 操作触发器:删除了之前在 BaseWindow 构造函数中调用 OpenComponent 以加载 CSWPFMasterDetailBinding 组件的代码。取而代之的是视图管理:处理 Window_Loaded Window_Closed 事件,分别加载和保存上次使用的视图。
  • 菜单:添加了两个菜单;第一个菜单允许进行基本功能,如 Create/Delete 视图,第二个菜单显示现有视图列表并允许在它们之间切换。在 BaseWindow 中添加了相关的 C# 代码来处理 GUI 事件并将其转发给 PerspectiveHelper 类。

第 2 个项目:容器组件:CSWPFMasterDetailBinding

目前打开的两个组件就像在 WPF Tab 控件中一样。这种呈现方式对于独立窗口(如 MasterComponent 实例)是相关的,但当一个窗口上的操作会修改另一个窗口时则不适用。

此项目使用视图来并排加载两个组件。

  • 资源:与 SofaBasicContainer 一样,导入 PerspectiveManager 助手。
  • 操作:在处理 SofaCommon PostOpen 事件的方法中添加了 perspectiveHelper.LoadPerspective("MainComponent") 方法,而在“Closed”事件中则添加了 perspectiveHelper.SaveCurrentPerspective()
  • 然后运行应用程序:第一次使用 LoadPerspective 方法时,视图不存在,因此没有效果。然后从菜单中加载 CSWPFMasterDetailBinding 组件,用户根据需要进行组织,并在关闭应用程序时通过 Closed 事件处理保存视图。这会创建视图,该视图成为应用程序的一部分。然后可以删除 PostOpen 事件处理中的两个 sofaContainer.OpenComponent 方法,因为组件将自动随视图一起打开。

历史

  • 2011 年 9 月 2 日:初始版本
© . All rights reserved.