Susan Warren
Keith Craig
Vertigo Software, Inc
适用于:
Microsoft?Office 2003 版本
Microsoft Visual Studio?.NET 2003
摘要:智能文档是一种强大的应用程序范型,但它本身并未利用基于 .NET 语言的面向对象的事件驱动特性。本文介绍了 Vertigo 托管智能文档包装 (Vertigo Managed Smart Documents Wrapper),它是一种托管包装,同时还是一组 Microsoft Visual Studio .NET 2003 项目模板。它使得利用基于 .NET 的语言进行智能文档的开发变得更加容易和经济高效。托管智能文档包装可从 Vertigo Software, Inc. 进行免费下载。
Vertigo 托管智能文档包装可从 Vertigo Software 公司网站获得。
简介 | |
智能文档基础知识 | |
使用 Visual Studio .NET 创建托管智能文档 | |
快速体验托管智能文档 | |
寻根究底 | |
自定义智能文档 | |
调试智能文档 | |
大胆设想:控件数组 | |
小结 |
我非常喜欢智能文档带来的用户体验。它们完成了一项惊人的工作,即通过将数据、过程和帮助恰当地集成到知识工作者在 Microsoft?Office Word 2003 或 Microsoft Office Excel 2003 中工作的地方,使得以文档为中心的任务变得更加流畅和高效。当我第一次见到智能文档时,我简直是兴奋异常:与构建、部署、支持又一个新的应用程序并对用户进行培训不同,该方法将应用程序智能直接放入文档本身。啊哈,多么美妙的主意!
但我同时还是一名使用面向对象的事件驱动编程模式开发企业生产率应用程序的忠实信徒。原因非常简单:开发、调试和维护用事件驱动的托管代码编写的应用程序,所花的代价要少得多。在我顿悟之后不久,我们收到了来自客户的有关开发智能文档解决方案的请求,于是我一头扎到智能文档开发领域之中,并且为获得一个使用这一强大的新应用程序范型的机会而感到激动。但是,没用多久我就意识到,实现智能文档意味着编写过程代码而不是面向对象的代码。一点都不好玩。
经过与合作开发者 Will Allan 以及合著者 Keith Craig 的共同努力,我着手创建了一组类和工具,以便使智能文档开发工作变得更容易、更高效,同时又能保留我们已经无比迷恋的基于 .NET 的开发模式的低拥有成本优势。本文介绍了我们的解决方案 — Vertigo 托管智能文档包装,并力图让读者迅速学会使用 Microsoft Visual Studio?.NET 2003 来开发智能文档。
托管智能文档包装提供了基于 .NET 的环境中缺少的一些智能文档开发环节。最重要的组件(也是我的 ASP.NET 的根本所在)实际上是过程性 ISmartDocument 接口的托管包装。该包装提供了“plumbing”(管线)以满足此接口的内部运转要求,从而使它能够充当文档的代码隐藏类(称为 ConfiguredSmartDocument)的基类。它从一个 XML 配置文件中读取文档任务窗格中元素的布局和事件 wire-up(接通)。ISmartDocument 的可编程性挂钩作为事件公开,您可以在文档的代码隐藏类中处理这些事件。
托管智能文档包装的另一个重要部件是一组新的 Visual Studio .NET 2003 项目类型,将这些项目类型与 Microsoft Visual Basic?.NET 和 Microsoft Visual C#? 开发语言配合使用,可以创建 Word 和 Excel 智能文档。正如您所看到的,一个智能文档解决方案由多个独立的文件组成。Visual Studio .NET 项目会创建一个初步的具有指导作用的解决方案,以便更加容易地管理这些文件以及它们之间的依赖性。
以下是与 Vertigo 托管智能文档包装一起安装的组件。
? | ISmartDocument 接口基于 .NET 的包装库 |
? | 用于在 Visual Basic .NET 和 C# 中创建托管智能文档的新型 Visual Studio .NET 2003 项目 |
? | 智能文档指令清单文件和 XML 配置文件的 Visual Studio .NET 语句完成架构 |
? | Visual Studio .NET C# 项目中的包装库的完整源代码 |
? | 一个演示如何使用包装库的示例 |
? | 文档 |
本文稍后将演练创建托管智能文档的过程,但首先让我们简要回顾一下智能文档的基础知识。
智能文档是 Word 2003 中的文档或 Excel 2003 中的工作簿,它与某个 XML 架构相关,从而使文档中的数据不仅是一个段落或一个单元格区域,而且具有上下文相关的标识。例如,它不是将一个单元格标识为类似 Sheet1!C34 的形式,更为可贵的是它知道该单元格包含支出报告的娱乐支出。特定于上下文的逻辑和用户交互是智能文档解决方案的另一个要素。当用户选择娱乐支出单元格时,智能文档可以显示特定于娱乐支出策略的任务窗格中的信息和操作。
文档和 XML 架构只是智能文档解决方案的多个文件其中的两个文件;其他文件支持保护、部署和更新智能文档背后的代码。智能文档解决方案由下列文件组成:
? | 智能文档。Word 文档或 Excel 电子表格。 |
? | 架构文件。定义文档的有意义区域的 XML 架构文件。 |
? | 操作处理程序代码。基于 .NET 的程序集 (DLL),它实现 ISmartDocument 接口并处理用户与任务窗格之间的交互。 |
? | XML 扩展包指令清单文件。一个 XML 文件,它指定完全启用特定智能文档解决方案所需的组件文件的标识和位置。 |
此外,托管智能文档包装还添加了下列文件:
? | SmartDocumentWrapper.dll。基于 .NET 的程序集,包含包装类。 |
? | Configuration.xml。一个XML 文件,它使用声明性 XML 语法定义了任务窗格的布局和功能。 |
这些文件如图 1 所示。
有关智能文档的详细信息,请参阅以下 SDK 文档:Office 2003 Smart Document Software Development Kit (SDK)。
在其文章 The Definitive "Hello World" Managed Smart Document Tutorial 中,John Durant 完成了一项卓越的工作,他描述了如何通过直接与 ISmartDocument 接口交互从头创建托管智能文档,并且提供了大量极其详细的细节。对于任何在基于 .NET 的环境中创建智能文档的开发人员而言,该文章中的信息都是很有用的,因此建议您能够阅读一下该文章。
但是在本文中,我们将演练如何通过随托管智能文档包装一起安装的库和项目模板来创建智能文档。
当您安装托管智能文档包装时,将添加新的 Visual Studio .NET 2003 项目模板,以便使用包装程序集来创建托管智能文档项目。分别针对 Visual C# 和 Visual Basic .NET 以及 Word 和 Excel 文档提供了模板。
要快速体验托管智能文档,请执行以下五个步骤:
? | 打开 Visual Studio .NET 2003。在 File 菜单上,指向 New,并单击 Project。将打开“新建项目”对话框: |
? | 选择项目类型,填写项目名称(以后更改会比较困难)和位置,然后单击 OK。该项目将打开,并且解决方案资源管理器中含有下列文件: |
? | 按 F5 启动项目编译,Word 将打开并显示 SmartDoc.doc 文档: |
? | 此时,尚未将扩展包附加到文档,所以文档还不具有“智能”!请按照文件中的绿色帮助文本中的说明来附加扩展包,将显示 Document Actions 任务窗格(此时,智能文档开始运行): |
? | 在 Document Actions 任务窗格中单击 Click Me! 可显示一个简单的消息框: |
就这么简单!
新的项目模板完成了大部分幕后工作,它们自动创建了以下内容:
? | XML 指令清单文件。Manifest.xml 列出了扩展包中包含的文件。 |
? | XML 架构文件。DocumentSchema.xsd 文件用于描述文档的逻辑结构。其中包括示例节,并带有如何对其进行扩展的注释。 |
? | XML 配置文件。Configuration.xml 使用一种简单的标记语言定义了 Document Actions 任务窗格控件及其属性。它含有示例文档操作节,并带有示例控件。 |
? | 代码隐藏代码类。OfficeCodeBehind 类派生自对 ISmartDocument 接口进行包装的类:ConfiguredSmartDocument。该类包含用于加载和初始化智能文档的事件处理程序,以及演示如何处理智能文档控件事件的控件事件处理程序示例。 |
? | 智能文档。这是一个 Word 2003 文档或 Excel 2003 工作簿,具体取决于所选的项目模板。该文档包含有关如何向文档附加扩展包的帮助文本。 |
此外,项目模板还配置了项目的调试和代码访问安全性。
? | 调试。按 F5 可在 Word 或 Excel 中启动智能文档,并将工作文件夹配置为含有 Manifest.xml 文件的文件夹。 |
? | 代码访问安全性。在项目创建时,将创建和自定义一个命令文件,并且自动执行该文件。它会为项目配置基于 URL 的代码访问安全性。该文件也被添加到项目中,并且进行了适当的注释,以便以后使用和修改。 |
现在,让我们继续寻根究底,了解一下刚刚创建的智能文档是如何工作的。请观察一下代码,Configuration.xml 文件的以下节定义了按钮:
<DocumentAction ActionXmlType="actionPertainsToEntireSchema" PaneCaption="Entire Schema Section"> <Control Name="Button1" Type="C_TYPE_BUTTON" Caption="This caption gets replaced and is never used!" OnSetCaption="Button1_SetCaption" OnPreRender="Button1_PreRender" OnAction="Button1_Action" /> <!-- TODO: Add additional controls here if desired. --> </DocumentAction>
标记被包装到 标记中。 标记定义了给定 ActionXmlType 的控件集,从本质上讲就是该文档的一个逻辑节。在此例中,“actionPertainsToEntireSchema”值意味着此 节中的控件出现在 Document Actions 任务窗格的顶部,而无论文档中的当前选择位置如何。
标记定义了按钮的名称、类型(按钮)、标题和数个事件处理程序。OnSetCaption 属性定义了用于设置标题的事件处理程序的名称。相关代码存在于 OfficeCodeBehind 类中:
Private Sub Button1_SetCaption(ByVal controlName As String, ByVal e As SetCaptionEventArgs) e.Caption = "Click Me!" End Sub
当控件即将呈现时,将按顺序引发 SetCaption 和 PreRender 事件。通过 SetCaption 可以动态设置标题。通过 PreRender 可以设置其他控件值和属性:
Private Sub Button1_PreRender(ByVal controlName As String, ByVal e As PreRenderEventArgs) ' Set the button caption to bold e.DisplayProps.FontWeight = "bold" End Sub
对于更为复杂的控件,可以使用 PreRender 事件实现更好的效果。例如,对于单选按钮组、列表框和组合框控件,可以在 PreRender 事件中动态设置要在相应控件中显示的项目。
最后,Configuration.xml 文件中的 OnAction 属性设置了在发生按钮事件时的“动作”事件处理程序的名称(按钮事件在用户单击按钮时引发):
Private Sub Button1_Action(ByVal controlName As String, ByVal e As ActionEventArgs) ' Show a message box when the button is clicked MessageBox.Show(string.Format("You clicked button '{0}'!", controlName)) End Sub
正如您所看到的,这在概念上与 ASP.NET 非常类似:
? | 控件以声明方式定义(在 .aspx 文件或 Configuration.xml 文件中)。 |
? | 事件处理程序配置控件并响应用户交互。它们的代码位于单独的文件中(在 ASP.NET 中为代码隐藏文件,在智能文档中为 OfficeCodeBehind 类)。 |
我们可以通过首先编辑 DocumentStructure.xsd 文件的内容,对文档的结构进行逻辑定义,从而对我们的测试智能文档进行自定义。然后,我们可以根据文档中当前选定内容的位置,在任务窗格中显示不同的控件。对于该示例,我们使用 DocumentStructure.xsd 文件的现有内容。
? | 首先,让我们从文档中删除现有的绿色帮助文本。 |
? | 下一步,单击任务窗格顶部的 Document Actions。将显示一个下拉列表;单击 XML Structure。任务窗格现在将如图所示: |
? | 在该任务窗格底部的列表框中单击 documentSections 元素。将显示一个对话框,询问您是希望将该元素应用于整个文档,还是仅应用于当前选定内容。 |
? | 选择 Apply to Entire Document。如果任务窗格中的 Show XML tags in the document 未选中,请将其选中。现在,您将看到文档中以粉红色标记表示的 XML 格式。 |
? | 接下来,请将文本“Section 1”和“Section 2”添加到文档正文的 标记内部。 |
? | 选择文本“Section 1”,然后在任务窗格底部的列表框中单击 Section 1。 |
? | 接下来,请选择文本“Section 2”,然后单击列表框中的 Section 2。该文档现在应该如图所示: 现在,我们已经将文本“Section 1”与 DocumentStructure.xsd 文件的 Section1 元素相关联,将文本“Section 2”与 Section2 元素相关联。 |
? | 单击任务窗格顶部的 XML Structure,然后单击 Document Actions 以再次显示 Document Actions 任务窗格。 |
现在,根据当前选定内容是否在文本“Section 1”或文本“Section 2”中,显示在任务窗格中的控件将相应更改。下面是当选定内容在“Section 1”中时显示的控件:
下面是当选定内容在“Section 2”中时显示的控件:
请观察一下任务窗格,只有当文档文本“Section 1”的某个部分被选中时,才会显示包含 Section 1 Button 控件的“Sample”节。这是因为 Section 1 Button 控件在 Configuration.xml 文件中被定义为驻留在 Section1 DocumentAction 节中:
<DocumentAction ActionXmlType="Section1" PaneCaption="Sample"> <Control Name="Section1Button" Type="C_TYPE_BUTTON" Caption="Section 1 Button" /> </DocumentAction>
目前,在 Configuration.xml 文件中还未定义对应于 Section2 的 DocumentAction 节。这就是当选定内容位于“Section 2”中时,在“Entire Schema Section”下面没有显示控件的原因(参见图 10)。
调试再简单不过了。只须在代码中设置一个断点,按 F5,并开始使用智能文档。当执行到达断点时,将在 Visual Studio 中暂停。使这一切变得如此容易的部分原因在于 Manifest.xml 文件对程序集使用 属性。该属性意味着不是将程序集下载到智能文档解决方案文件夹中,而是从其现有位置运行。这意味着不必移动、删除扩展包然后将其附加到文档以获取代码的更新副本。
作为一个简单示例,请在 Button1_SetCaption 方法中设置一个断点,然后按 F5:
这里,您可以在调试器弹出式信息框中看到 Configuration.xml 文件中的原始标题 (e.Caption = "This caption gets replaced and is never used!")。代码将要用新标题 "Click Me!" 替换现有的值。
如果您在设计时知道需要多少个控件并且知道这些控件的类型,则上述模型可以很好地发挥作用。这是智能文档开发中最常见的情形。然而,在某些情形下,如果能够基于只有在运行时才能获得的信息(例如,数据库中的信息),用控件动态地填充任务窗格,将会非常棒。控件数组就适用于这种情况。
控件数组的思想非常简单:在 Configuration.xml 中希望动态添加控件的位置放置一个占位符,然后使用 ControlArrayInitialize 事件来填充控件。您可以具有任意数量的控件数组(尽管当前的智能文档实现将单个 DocumentAction 节中的控件个数限制为不超过 256 个)。
让我们看一个使用控件数组的简单示例。将以下代码添加到 Configuration.xml 文件的“actionPertainsToEntireSchema” 节中,并使其恰好位于 Button1 控件的下方:
<Control Name="MyControlArray" Type="ControlArray" OnControlArrayInitialize="MyControlArray_Initialize"/>
接下来,将以下 ControlArrayInitialize 事件处理程序添加到 OfficeCodeBehind 类中:
Private Sub MyControlArray_Initialize(ByVal controlName As String, ByVal e As ControlArrayInitializeEventArgs) ' Create a label: Dim label As SmartDocumentConfiguration.ControlRow label = e.ControlTable.NewControlRow() label.Name = "DynamicLabel" label.Caption = "Dynamic Label Control" label.Type = "C_TYPE_LABEL" e.ControlTable.AddControlRow(label) ' Create a button: Dim button As SmartDocumentConfiguration.ControlRow button = e.ControlTable.NewControlRow() button.Name = "DynamicButton" button.Caption = "Dynamic Button" button.Type = "C_TYPE_BUTTON" e.ControlTable.AddControlRow(button) ' Add the FontWeight = 'bold' property to the button Dim buttonProperty As SmartDocumentConfiguration.PropertyRow buttonProperty = e.PropertyTable.NewPropertyRow() buttonProperty.Name = "FontWeight" buttonProperty.Property_Text = "bold" e.PropertyTable.AddPropertyRow(buttonProperty) ' Associate this property with the button control buttonProperty.SetParentRow(button) End Sub
现在,按 F5 运行该项目。您将注意到的第一件事情是控件数组没有出现,它不起作用!这是因为我们尚未更新扩展包中的文件。简而言之,当您将扩展包附加到文档时,它会将文件复制到一个新位置。这么做的原因是当您将扩展包附加到文档时,可以简化智能文档部署;文件将被下载(大概是从服务器)到本地计算机。但是,在开发过程中需要费一些力气:文件存在于两个位置:一组文件在 Visual Studio 项目文件夹中,另一组文件在智能文档解决方案文件夹中。(智能文档解决方案文件夹位于 C:\Documents and Settings\user\Local Settings\Application Data\Microsoft\Schemas\solutionNamespace\solutionID。)随托管智能文档包装一起安装的文档介绍了一个过程,可以使用该过程重新配置项目,从而无须手动删除和重新附加扩展包来更新 Configuration.xml 文件。
? | 在 Word Tools 菜单上,单击 Templates and Add-Ins.?.?.,然后单击 XML Expansion Pack 选项卡。 |
? | 单击 Remove 将扩展包从文档中分离,然后单击列表中的扩展包名称,单击 Delete,再单击 Yes 确认删除。 |
? | 然后,单击 Add.-Ins ,浏览到 Manifest.xml 文件,再单击 Open。 |
? | 单击 No 以避免重新激活扩展包指令清单安全性,最后单击 OK 以附加扩展包。 |
当扩展包已经加载并且智能文档开始运行时,Document Actions 任务窗格将如图所示:
请注意,按钮中的字体为粗体(由于控件上设置的属性),并且控件数组中的控件被添加到 Configuration.xml 文件中控件数组占位符所在的位置。
托管智能文档包装将用户的智能文档经验与面向对象的、声明性的、事件驱动编程的生产率优势结合起来。此外,新的项目模板能够自动完成创建智能文档项目的大部分乏味的工作。托管智能文档包装还安装了大量的文档以及一个用 Visual Basic .NET 和 Word 创建的示例智能文档,以便演示几乎涵盖了该包装程序集所有方面的用法。无论您是一位从未接触过智能文档的面向 .NET 的开发人员,还是一个在创建智能文档方面具有丰富经验的面向 .NET 的开发人员,托管智能文档包装都可为您带来大量好处。
关于作者
Susan Warren是 Microsoft 电子商务解决方案金牌认证合作伙伴 Vertigo Software, Inc. 的一位高级软件工程师。她最近任 DevDays 2004 特别推介的 IssueVision 智能客户端应用程序的设计和开发主持人。在加入 Vertigo 以前,Susan 是 Microsoft 的一名项目经理,负责 ASP.NET 中的网页和控件框架以及 Visual Studio .NET 中的 Web Matrix 和 Web 窗体设计器。
Keith Craig 是 Vertigo Software Inc 的一位高级软件工程师。在加入 Vertigo 之前,他开发了一些 ASP.NET 和 ASP Web 应用程序、SQL Server 数据库、Visual Basic 6 客户端-服务器数据仓库应用程序以及其他许多软件项目。Keith 具有 University of California at Santa Barbara 的物理学博士学位,并且是一位 Microsoft .NET 认证解决方案开发专家 (MCSD)。