如何访问 Office 互操作对象

C# 具有一些功能,可简化对 Office API 对象的访问。 这些新功能包括命名实参和可选实参、名为 dynamic 的新类型,以及在 COM 方法中将实参传递为引用形参(就像它们是值形参)的功能。

在本文中,你将使用这些新功能来编写代码,创建并显示 Microsoft Office Excel 工作表。 你将编写代码来添加包含链接到 Excel 工作表的图标的 Office Word 文档。

若要完成本演练,你的计算机上必须安装 Microsoft Office Excel 2007 和 Microsoft Office Word 2007 或更高版本。

注意

以下说明中的某些 Visual Studio 用户界面元素在计算机上出现的名称或位置可能会不同。 这些元素取决于你所使用的 Visual Studio 版本和你所使用的设置。 有关详细信息,请参阅个性化设置 IDE

重要

VSTO (Visual Studio Tools for Office) 依赖于 .NET Framework。 COM 加载项也可以使用 .NET Framework 编写。 不能使用 .NET Core 和 .NET 5+(最新版本的 .NET)创建 Office 加载项。 这是因为 .NET Core/.NET 5+ 无法在同一进程中与 .NET Framework 协同工作,并可能导致加载项加载失败。 可以继续使用 .NET Framework 编写适用于 Office 的 VSTO 和 COM 加载项。 Microsoft 不会更新 VSTO 或 COM 加载项平台以使用 .NET Core 或 .NET 5+。 可以利用 .NET Core 和 .NET 5+(包括 ASP.NET Core)创建 Office Web 加载项的服务器端。

创建新的控制台应用程序

  1. 启动 Visual Studio。
  2. “文件” 菜单上,指向 “新建”,然后选择 “项目”。 此时将出现“新建项目” 对话框。
  3. 在“已安装的模板”窗格中,展开“C#”,然后选择“Windows”。
  4. 查看“新建项目”对话框的顶部,确保将“.NET Framework 4”(或更高版本)选为目标框架。
  5. “模板”窗格中,选择“控制台应用程序”
  6. 在“名称”字段中键入项目的名称。
  7. 选择“确定”。

新项目将出现在“解决方案资源管理器”中。

添加引用

  1. 在“解决方案资源管理器”中,右键单击你的项目名称,然后选择“添加引用”。 此时会显示“添加引用”对话框。
  2. 在“程序集”页上,在“组件名称”列表中选择“Microsoft.Office.Interop.Word”,然后按住 Ctrl 键并选择“Microsoft.Office.Interop.Excel”。 如果没有看到程序集,可能需要进行安装。 请参阅如何:安装 Office 主互操作程序集
  3. 选择“确定” 。

添加必要的 using 指令

在“解决方案资源管理器”中,右键单击“Program.cs”文件,然后选择“查看代码”。 将以下 using 指令添加到代码文件的顶部:

using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;

创建银行帐户列表

将以下类定义粘贴到“Program.cs”中的 Program 类下。

public class Account
{
    public int ID { get; set; }
    public double Balance { get; set; }
}

将以下代码添加到 Main 方法,以创建包含两个帐户的 bankAccounts 列表。

// Create a list of accounts.
var bankAccounts = new List<Account> {
    new Account {
                  ID = 345678,
                  Balance = 541.27
                },
    new Account {
                  ID = 1230221,
                  Balance = -127.44
                }
};

声明将帐户信息导出到 Excel 的方法

  1. 将以下方法添加到 Program 类以设置 Excel 工作表。 方法 Add 有一个可选参数,用于指定特定的模板。 如果希望使用形参的默认值,你可以借助可选形参以忽略该形参的实参。 由于你没有提供参数,Add 会使用默认模板并创建新的工作簿。 C# 早期版本中的等效语句要求提供一个占位符参数:ExcelApp.Workbooks.Add(Type.Missing)
static void DisplayInExcel(IEnumerable<Account> accounts)
{
    var excelApp = new Excel.Application();
    // Make the object visible.
    excelApp.Visible = true;

    // Create a new, empty workbook and add it to the collection returned
    // by property Workbooks. The new workbook becomes the active workbook.
    // Add has an optional parameter for specifying a particular template.
    // Because no argument is sent in this example, Add creates a new workbook.
    excelApp.Workbooks.Add();

    // This example uses a single workSheet. The explicit type casting is
    // removed in a later procedure.
    Excel._Worksheet workSheet = (Excel.Worksheet)excelApp.ActiveSheet;
}

DisplayInExcel 的末尾添加以下代码。 代码将值插入工作表第一行的前两列。

// Establish column headings in cells A1 and B1.
workSheet.Cells[1, "A"] = "ID Number";
workSheet.Cells[1, "B"] = "Current Balance";

DisplayInExcel 的末尾添加以下代码。 foreach 循环将帐户列表中的信息放入工作表连续行的前两列。


var row = 1;
foreach (var acct in accounts)
{
    row++;
    workSheet.Cells[row, "A"] = acct.ID;
    workSheet.Cells[row, "B"] = acct.Balance;
}

DisplayInExcel 的末尾添加以下代码以将列宽调整为适合内容。

workSheet.Columns[1].AutoFit();
workSheet.Columns[2].AutoFit();

早期版本的 C# 要求显式强制转换这些操作,因为 ExcelApp.Columns[1] 返回 ObjectAutoFit 为 Excel Range 方法。 以下各行显示强制转换。

((Excel.Range)workSheet.Columns[1]).AutoFit();
((Excel.Range)workSheet.Columns[2]).AutoFit();

C# 自动将返回的 Object 转换为 dynamic,前提是程序集由 EmbedInteropTypes 编译器选项引用,或 Excel 的“嵌入互操作类型”属性为 true。 True 是此属性的默认值。

运行项目

Main 的末尾添加以下行。

// Display the list in an Excel spreadsheet.
DisplayInExcel(bankAccounts);

按 Ctrl+F5。 出现包含两个帐户数据的 Excel 工作表。

添加 Word 文档

以下代码可以打开 Word 应用程序并创建链接到 Excel 工作表的图标。 将方法 CreateIconInWordDoc(在此步骤后面提供)粘贴到 Program 类中。 CreateIconInWordDoc 使用命名参数和可选参数来降低对 AddPasteSpecial 方法调用的复杂性。 这些调用合并了其他两项新功能,这两项新功能简化了具有引用参数的 COM 方法的调用。 首先,你可以将实参发送到引用形参,就像它们是值形参一样。 即,你可以直接发送值,而无需为每个引用参数创建变量。 编译器会生成临时变量以保存参数值,并将在你从调用返回时丢弃变量。 其次,你可以忽略参数列表中的 ref 关键字。

Add 方法有四个引用参数,所有引用参数都是可选的。 如果希望使用其默认值,可以忽略任何或所有形参的实参。

PasteSpecial 方法可插入剪贴板的内容。 该方法有七个引用参数,所有引用参数都是可选的。 以下代码为其中两个形参指定实参:Link 用于创建指向剪贴板内容源的链接,DisplayAsIcon 用于将链接显示为图标。 可以对其中两个实参(忽略其他实参)使用命名实参。 尽管这些实参是引用形参,你也不必使用 ref 关键字,或者创建变量以实参形式发送。 你可以直接发送值。

static void CreateIconInWordDoc()
{
    var wordApp = new Word.Application();
    wordApp.Visible = true;

    // The Add method has four reference parameters, all of which are
    // optional. Visual C# allows you to omit arguments for them if
    // the default values are what you want.
    wordApp.Documents.Add();

    // PasteSpecial has seven reference parameters, all of which are
    // optional. This example uses named arguments to specify values
    // for two of the parameters. Although these are reference
    // parameters, you do not need to use the ref keyword, or to create
    // variables to send in as arguments. You can send the values directly.
    wordApp.Selection.PasteSpecial( Link: true, DisplayAsIcon: true);
}

Main 的末尾添加以下语句。

// Create a Word document that contains an icon that links to
// the spreadsheet.
CreateIconInWordDoc();

DisplayInExcel 的末尾添加以下语句。 Copy 方法可将工作表添加到剪贴板。

// Put the spreadsheet contents on the clipboard. The Copy method has one
// optional parameter for specifying a destination. Because no argument
// is sent, the destination is the Clipboard.
workSheet.Range["A1:B3"].Copy();

按 Ctrl+F5。 将出现包含图标的 Word 文档。 双击该图标以将工作表置于前台。

设置嵌入互操作类型属性

当调用运行时不需要主互操作程序集 (PIA) 的 COM 类型时,可能实现其他增强功能。 删除 PIA 的依赖项可实现版本独立性并且更易于部署。 若要详细了解不使用 PIA 编程的优势,请参阅演练:嵌入托管程序集中的类型

此外,由于 dynamic 类型表示在 COM 方法中声明的必需类型和返回类型,因此更易于编程。 具有类型 dynamic 的变量在运行时以前均不会计算,从而消除了显式强制转换的必要性。 有关更多信息,请参见使用类型 dynamic

默认行为是嵌入类型信息,而不是使用 PIA。 由于该默认行为,之前的几个示例也得到简化。 不需要任何显式强制转换。 例如,worksheetDisplayInExcel 的声明会写为 Excel._Worksheet workSheet = excelApp.ActiveSheet 而非 Excel._Worksheet workSheet = (Excel.Worksheet)excelApp.ActiveSheet。 在相同方法中对 AutoFit 的调用还将要求在不进行默认行为的情况下显式强制转换,因为 ExcelApp.Columns[1] 返回 Object,并且 AutoFit 为 Excel 方法。 以下代码显示强制转换。

((Excel.Range)workSheet.Columns[1]).AutoFit();
((Excel.Range)workSheet.Columns[2]).AutoFit();

若要更改默认行为并使用 PIA 代替嵌入类型信息,请展开“解决方案资源管理器”中的“引用”节点,然后选择“Microsoft.Office.Interop.Excel”或“Microsoft.Office.Interop.Word”。 如果看不到“属性”窗口,请按 F4。 在属性列表中找到“嵌入互操作类型”,将其值更改为“False”。 同样地,还可以通过在命令提示符处使用 References 编译器选项代替 EmbedInteropTypes 进行编译。

将其他格式添加到表格

将在 AutoFit 中对 DisplayInExcel 的两个调用替换为以下语句。

// Call to AutoFormat in Visual C# 2010.
workSheet.Range["A1", "B3"].AutoFormat(
    Excel.XlRangeAutoFormat.xlRangeAutoFormatClassic2);

AutoFormat 方法有七个值参数,所有引用参数都是可选的。 使用命名自变量和可选自变量,你可以为这些自变量中的所有或部分提供自变量,也可以不为它们中的任何一个提供。 在上一条语句中,仅为其中一个形参 Format 提供了实参。 由于 Format 是参数列表中的第一个参数,因此无需提供参数名称。 但是,如果包含参数名称,语句可能更易于理解,如以下代码所示。

// Call to AutoFormat in Visual C# 2010.
workSheet.Range["A1", "B3"].AutoFormat(Format:
    Excel.XlRangeAutoFormat.xlRangeAutoFormatClassic2);

按 Ctrl+F5 查看结果。 可以在列出的 XlRangeAutoFormat 枚举中找到其他格式。

示例

以下代码显示完整示例。

using System.Collections.Generic;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;

namespace OfficeProgrammingWalkthruComplete
{
    class Walkthrough
    {
        static void Main(string[] args)
        {
            // Create a list of accounts.
            var bankAccounts = new List<Account>
            {
                new Account {
                              ID = 345678,
                              Balance = 541.27
                            },
                new Account {
                              ID = 1230221,
                              Balance = -127.44
                            }
            };

            // Display the list in an Excel spreadsheet.
            DisplayInExcel(bankAccounts);

            // Create a Word document that contains an icon that links to
            // the spreadsheet.
            CreateIconInWordDoc();
        }

        static void DisplayInExcel(IEnumerable<Account> accounts)
        {
            var excelApp = new Excel.Application();
            // Make the object visible.
            excelApp.Visible = true;

            // Create a new, empty workbook and add it to the collection returned
            // by property Workbooks. The new workbook becomes the active workbook.
            // Add has an optional parameter for specifying a particular template.
            // Because no argument is sent in this example, Add creates a new workbook.
            excelApp.Workbooks.Add();

            // This example uses a single workSheet.
            Excel._Worksheet workSheet = excelApp.ActiveSheet;

            // Earlier versions of C# require explicit casting.
            //Excel._Worksheet workSheet = (Excel.Worksheet)excelApp.ActiveSheet;

            // Establish column headings in cells A1 and B1.
            workSheet.Cells[1, "A"] = "ID Number";
            workSheet.Cells[1, "B"] = "Current Balance";

            var row = 1;
            foreach (var acct in accounts)
            {
                row++;
                workSheet.Cells[row, "A"] = acct.ID;
                workSheet.Cells[row, "B"] = acct.Balance;
            }

            workSheet.Columns[1].AutoFit();
            workSheet.Columns[2].AutoFit();

            // Call to AutoFormat in Visual C#. This statement replaces the
            // two calls to AutoFit.
            workSheet.Range["A1", "B3"].AutoFormat(
                Excel.XlRangeAutoFormat.xlRangeAutoFormatClassic2);

            // Put the spreadsheet contents on the clipboard. The Copy method has one
            // optional parameter for specifying a destination. Because no argument
            // is sent, the destination is the Clipboard.
            workSheet.Range["A1:B3"].Copy();
        }

        static void CreateIconInWordDoc()
        {
            var wordApp = new Word.Application();
            wordApp.Visible = true;

            // The Add method has four reference parameters, all of which are
            // optional. Visual C# allows you to omit arguments for them if
            // the default values are what you want.
            wordApp.Documents.Add();

            // PasteSpecial has seven reference parameters, all of which are
            // optional. This example uses named arguments to specify values
            // for two of the parameters. Although these are reference
            // parameters, you do not need to use the ref keyword, or to create
            // variables to send in as arguments. You can send the values directly.
            wordApp.Selection.PasteSpecial(Link: true, DisplayAsIcon: true);
        }
    }

    public class Account
    {
        public int ID { get; set; }
        public double Balance { get; set; }
    }
}

请参阅