在运行时扩展 VSTO 外接程序中的 Word 文档和 Excel 工作簿

你可以通过下列方式使用 VSTO 外接程序来自定义 Word 文档和 Excel 工作簿:

  • 将托管控件添加到任意打开的文档或工作表。

  • 将 Excel 工作表上的现有列表对象转换为扩展 ListObject ,后者可公开事件并能通过使用 Windows 窗体数据绑定模型绑定到数据。

  • 访问由 Word 和 Excel 公开的用于特定文档、工作簿和工作表的应用程序级事件。

    若要使用此功能,请在扩展文档或工作簿的运行时生成一个对象。

    适用于:。本文中的信息适用于以下应用程序的 VSTO 外接程序项目:Excel 和 Word。 有关详细信息,请参阅按 Office 应用程序和项目类型提供的功能

在 VSTO 外接程序中生成扩展对象

扩展对象 是由 Visual Studio Tools for Office Runtime 提供的类型的实例,该运行时可将功能添加到存在于 Word 或 Excel 对象模型中的本机对象(称为 本机 Office 对象)。 若要生成 Word 或 Excel 对象的扩展对象,请使用 GetVstoObject 方法。 第一次为指定的 Word 或 Excel 对象调用 GetVstoObject 方法时,会返回一个扩展指定对象的新对象。 每次调用方法并指定相同 Word 或 Excel 对象时,它将返回相同的扩展对象。

扩展对象的类型具有与本机 Office 对象的类型相同的名称,但该类型是在 Microsoft.Office.Tools.ExcelMicrosoft.Office.Tools.Word 命名空间中定义的。 例如,如果调用 GetVstoObject 方法来扩展 Document 对象,则该方法将返回 Document 对象。

GetVstoObject 方法应主要用于 VSTO 外接程序项目。 你还可以在文档级项目中使用这些方法,但它们的行为有所不同,并且用途更少。

若要确定是否为特定的本机 Office 对象生成了扩展对象,请使用 HasVstoObject 方法。 有关详细信息,请参阅确定是否扩展了 Office 对象

生成主机项

使用 GetVstoObject 扩展文档级对象(即 WorkbookWorksheetDocument)时,返回的对象称为主机项。 主机项是可以包含其他对象的类型,包括其他扩展对象和控件。 它类似于在 Word 或 Excel 主互操作程序集中相应的类型,但它具有附加功能。 有关主机项的详细信息,请参阅主机项和主机控件概述

生成主机项后,可将其用于将托管控件添加到文档、工作簿或工作表中。 有关详细信息,请参阅向文档和工作表中添加托管控件

若要生成 Word 文档的主机项

  • 以下代码示例演示了如何生成活动文档的主机项。

    if (Globals.ThisAddIn.Application.Documents.Count > 0)
    {
        Microsoft.Office.Interop.Word.Document nativeDocument =
            Globals.ThisAddIn.Application.ActiveDocument;
        Microsoft.Office.Tools.Word.Document vstoDocument =
            Globals.Factory.GetVstoObject(nativeDocument);
    }
    

若要生成 Excel 工作簿的主机项

  • 以下代码示例演示了如何生成活动工作簿的主机项。

    Microsoft.Office.Interop.Excel.Workbook nativeWorkbook = 
        Globals.ThisAddIn.Application.ActiveWorkbook;
    if (nativeWorkbook != null)
    {
        Microsoft.Office.Tools.Excel.Workbook vstoWorkbook = 
            Globals.Factory.GetVstoObject(nativeWorkbook);
    }
    

若要生成 Excel 工作表的主机项

  • 以下代码示例演示了如何为项目中的活动工作表生成主机项。

    Microsoft.Office.Interop.Excel.Worksheet nativeWorksheet =
        Globals.ThisAddIn.Application.ActiveSheet;
    if (nativeWorksheet != null)
    {
        Microsoft.Office.Tools.Excel.Worksheet vstoSheet = 
            Globals.Factory.GetVstoObject(nativeWorksheet);
    }
    

生成 ListObject 主机控件

当使用 GetVstoObject 方法扩展 ListObject 时,该方法将返回一个 ListObjectListObject 具有原始 ListObject 的所有功能。 同时还具有附加功能,可以使用 Windows 窗体数据绑定模型绑定到数据。 有关详细信息,请参阅 ListObject 控件

若要为 ListObject 生成主机控件

  • 以下代码示例演示了如何为项目中活动工作表内第一个 ListObject 生成 ListObject

    Microsoft.Office.Interop.Excel.Worksheet sheet =
        Globals.ThisAddIn.Application.ActiveSheet;
    if (sheet.ListObjects.Count > 0)
    {
        Excel.ListObject listObject = 
            sheet.ListObjects[1];
        Microsoft.Office.Tools.Excel.ListObject vstoListObject =
            Globals.Factory.GetVstoObject(listObject);
    }
    

向文档和工作表中添加托管控件

在生成 DocumentWorksheet后,你可以将控件添加到这些扩展对象表示的文档或工作表。 若要添加控件,请使用 DocumentWorksheetControls 属性。 有关详细信息,请参阅在运行时向 Office 文档添加控件

可以添加 Windows 窗体控件或 主机控件。 主机控件是 Visual Studio Tools for Office 运行时提供的控件,将相应的控件包装在 Word 或 Excel 主互操作程序集中。 主机控件公开基础本机 Office 对象的所有行为。 同时还引发事件,可以使用 Windows 窗体数据绑定模型绑定到数据。 有关详细信息,请参阅主机项和主机控件概述

注意

不能通过使用 VSTO 外接程序将 XmlMappedRange 控件添加到工作表,或是将 XMLNodeXMLNodes 控件添加到文档。 不能以编程方式添加这些主机控件。 有关详细信息,请参阅主机项和主机控件的编程限制

保留和删除控件

当你将托管控件添加到文档或工作表中时,在保存文档并将其关闭时,不会保留这些控件。 所有主机控件都将被删除,仅留下基础本机 Office 对象。 例如,一个 ListObject 将变成 ListObject。 所有 Windows 窗体控件也将被删除,但控件的 ActiveX 包装会留在文档中。 你必须在 VSTO 外接程序中包括清理控件的代码,或包括在下次打开该文档时重新创建这些控件的代码。 有关详细信息,请参阅在 Office 文档中暂留动态控件

访问文档和工作簿上的应用程序级事件

本机 Word 和 Excel 对象模型中的某些文档、工作簿和工作表事件仅在应用程序级引发。 例如,在 Word 中打开文档时会引发 DocumentBeforeSave 事件,但是此事件是在 Application 类而不是 Document 类中定义的。

当在 VSTO 外接程序中仅使用本机 Office 对象时,必须处理这些应用程序级的事件,然后编写附加代码以确定引发该事件的文档是否为你已自定义的文档。 主机项可提供这些文档级事件,因此,更易于处理特定文档的事件。 你可以生成一个主机项,然后处理该主机项的事件。

使用本机 Word 对象的示例

以下代码示例演示了如何处理 Word 文档的应用程序级事件。 CreateDocument 方法可创建一个新文档,然后定义一个 DocumentBeforeSave 事件处理程序,以防止保存此文档。 该事件是为 Application 对象引发的应用程序级事件,事件处理程序必须将 Doc 参数与 document1 对象进行比较,以确定 document1 是否表示保存的文档。

private Word.Document document1 = null;

private void CreateDocument1()
{
    document1 = this.Application.Documents.Add(ref missing,
        ref missing, ref missing, ref missing);
    this.Application.DocumentBeforeSave += 
        new Word.ApplicationEvents4_DocumentBeforeSaveEventHandler(
        Application_DocumentBeforeSave);
}

private void Application_DocumentBeforeSave(Word.Document Doc, 
    ref bool SaveAsUI, ref bool Cancel)
{
    if (Type.ReferenceEquals(Doc, document1)) 
    {
        Cancel = true;
    }
}

使用主机项的示例

以下代码示例通过处理 BeforeSave 主机项的 Document 事件简化了此过程。 这些示例中的 CreateDocument2 方法生成了扩展 Document 对象的 document2,然后定义一个 BeforeSave 事件处理程序,防止保存该文档。 只有在保存 document2 时才会调用事件处理程序,并且可以取消保存操作,而无需做任何额外的工作来验证保存了哪个文档。

以下代码示例演示了此任务。

private Word.Document document2 = null;
private Microsoft.Office.Tools.Word.Document vstoDocument = null;

private void CreateDocument2()
{
    document2 = this.Application.Documents.Add(ref missing,
        ref missing, ref missing, ref missing);
    vstoDocument = Globals.Factory.GetVstoObject(document2);
    vstoDocument.BeforeSave += new SaveEventHandler(vstoDocument_BeforeSave);
}

private void vstoDocument_BeforeSave(object sender, SaveEventArgs e)
{
    e.Cancel = true;
}

确定是否扩展了 Office 对象

若要确定是否为特定的本机 Office 对象生成了扩展对象,请使用 HasVstoObject 方法。 如果已经生成了扩展对象,则此方法返回 true

使用 Globals.Factory.HasVstoObject 方法。 在希望为扩展对象测试的本机 Word 或 Excel 对象中传递,如 DocumentWorksheet

当希望仅在指定 Office 对象包括扩展对象的情况下运行代码时,可以使用 HasVstoObject 方法。 例如,如果有一个 Word VSTO 外接程序,该外接程序处理 DocumentBeforeSave 事件,以在保存文档之前从文档中删除托管控件,请使用 HasVstoObject 方法来确定文档是否已扩展。 如果文档未被扩展,则它不可能具有托管控件;并且事件处理程序可以返回而不尝试清理文档上的控件。