Visual Studio 2010 在 C# 和 Visual Basic 中引入了可改善 Microsoft Office 编程的新功能。每种语言都新增了其他语言中已存在的功能。
C# 中的新功能包括命名参数和可选参数、类型为 dynamic 的返回值、在 COM 编程中省略 ref 关键字以及访问索引属性的功能。Visual Basic 中的新功能包括自动实现的属性、lambda 表达式中的语句以及集合初始值设定项。
这两种语言都能够嵌入类型信息,从而允许部署与 COM 组件交互的程序集,而无需将主互操作程序集 (PIA) 部署到用户的计算机。有关更多信息,请参见演练:嵌入托管程序集中的类型(C# 和 Visual Basic)。
此演练在 Office 编程的上下文中演示了这些新功能,但其中许多功能在一般编程中也非常有用。在演练中,将首先使用 Excel 外接应用程序创建一个 Excel 工作簿。然后将创建一个 Word 文档,其中包含指向该工作簿的链接。最后,您将了解如何能够启用和禁用 PIA 依赖项。
系统必备
计算机上必须安装了 Microsoft Office Excel 2010 或 2007 和 Microsoft Office Word 2010 或 2007 才能完成此演练。
如果使用的操作系统低于 Windows Vista,请务必安装 .NET Framework 2.0。
说明 |
|---|
对于在以下说明中使用的某些 Visual Studio 用户界面元素,您的计算机可能会显示不同的名称或位置。这些元素取决于您所使用的 Visual Studio 版本和您所使用的设置。有关更多信息,请参见 Visual Studio 设置。 |
安装 Excel 外接应用程序
启动 Visual Studio。
在**“文件”菜单上指向“新建”,再单击“项目”**。
在**“已安装的模板”窗格中,展开“Visual Basic”或“Visual C#”,展开“Office”,然后单击“2010”(如果使用的是 Office 2007,则单击“2007”**)。
在**“模板”窗格中,单击“Excel 2010 外接程序”(或“Excel 2007 外接程序”**)。
查看**“模板”窗格的顶部,确保“.NET Framework 4”显示在“目标框架”**框中。
如果需要,在**“名称”**框中键入项目的名称。
单击**“确定”**。
新项目出现在**“解决方案资源管理器”**中。
添加引用
在**“解决方案资源管理器”中,右击项目的名称,然后单击“添加引用”。将显示“添加引用”**对话框。
在**“.NET”选项卡上的“组件名称”列表中选择“Microsoft.Office.Interop.Excel”14.0.0.0 版(对于 Excel 2007,则为 12.0.0.0 版),然后按住 Ctrl 键并选择“Microsoft.Office.Interop.Word”**14.0.0.0 版(对于 Word 2007,则为 12.0.0.0 版)。
单击**“确定”**。
添加必要的 Imports 语句或 using 指令
在**“解决方案资源管理器”中,右击“ThisAddIn.vb”或“ThisAddIn.cs”文件,然后单击“查看代码”**。
将以下 Imports 语句 (Visual Basic) 或 using 指令 (C#) 添加到代码文件的顶部(如果这些语句尚不存在)。
Imports Microsoft.Office.Interopusing System.Collections.Generic; using Excel = Microsoft.Office.Interop.Excel; using Word = Microsoft.Office.Interop.Word;
创建银行帐户的列表
在**“解决方案资源管理器”中,右击项目的名称,单击“添加”,然后单击“类”。如果使用 Visual Basic,请将类命名为 Account.vb,或者,如果使用 C#,则命名为 Account.cs。单击“添加”**。
用下面的代码替换 Account 类的定义。类定义使用“自动实现的属性”,这是 Visual Studio 2010 中的 Visual Basic 的一项新功能。有关更多信息,请参见自动实现的属性 (Visual Basic)。
Public Class Account Property ID As Integer = -1 Property Balance As Double End Classclass Account { public int ID { get; set; } public double Balance { get; set; } }若要创建包含两个帐户的 bankAccounts 列表,请将以下代码添加到 ThisAddIn.vb 或 ThisAddIn.cs 中的 ThisAddIn_Startup 方法。列表声明使用“集合初始值设定项”,这是 Visual Studio 2010 中的 Visual Basic 的一项新功能。有关更多信息,请参见集合初始值设定项 (Visual Basic)。
Dim bankAccounts As New List(Of Account) From { New Account With { .ID = 345, .Balance = 541.27 }, New Account With { .ID = 123, .Balance = -127.44 } }var bankAccounts = new List<Account> { new Account { ID = 345, Balance = 541.27 }, new Account { ID = 123, Balance = -127.44 } };
将数据导出到 Excel
在相同文件中,将以下方法添加到 ThisAddIn 类。该方法设置 Excel 工作簿并将数据导出到其中。
Sub DisplayInExcel(ByVal accounts As IEnumerable(Of Account), ByVal DisplayAction As Action(Of Account, Excel.Range)) With Me.Application ' Add a new Excel workbook. .Workbooks.Add() .Visible = True .Range("A1").Value = "ID" .Range("B1").Value = "Balance" .Range("A2").Select() For Each ac In accounts DisplayAction(ac, .ActiveCell) .ActiveCell.Offset(1, 0).Select() Next ' Copy the results to the Clipboard. .Range("A1:B3").Copy() End With End Subvoid DisplayInExcel(IEnumerable<Account> accounts, Action<Account, Excel.Range> DisplayFunc) { var excelApp = this.Application; // Add a new Excel workbook. excelApp.Workbooks.Add(); excelApp.Visible = true; excelApp.Range["A1"].Value = "ID"; excelApp.Range["B1"].Value = "Balance"; excelApp.Range["A2"].Select(); foreach (var ac in accounts) { DisplayFunc(ac, excelApp.ActiveCell); excelApp.ActiveCell.Offset[1, 0].Select(); } // Copy the results to the Clipboard. excelApp.Range["A1:B3"].Copy(); }此方法中使用了两个新的 C# 功能。这两种功能都是 Visual Basic 中的已有功能。
方法 Add 具有用于指定特定模板的可选参数。利用可选形参(Visual C# 2010 中的新功能),您将能够在希望使用形参的默认值的情况下省略该形参的实参。由于在前面的示例中未发送参数,因此 Add 使用默认模板并创建一个新工作簿。C# 早期版本中的等效语句需要占位符参数:excelApp.Workbooks.Add(Type.Missing)。
有关更多信息,请参见命名实参和可选实参(C# 编程指南)。
Range 对象的 Range 和 Offset 属性使用索引属性功能。利用此功能,您可以通过使用以下典型的 C# 语法从 COM 类型中使用这些属性。还可利用索引属性使用 Range 对象的 Value 属性,而不必使用 Value2 属性。Value 属性是经过索引的,但此索引是可选的。在下面的示例中,可选参数和索引属性协同工作。
// Visual C# 2010 provides indexed properties for COM programming. excelApp.Range["A1"].Value = "ID"; excelApp.ActiveCell.Offset[1, 0].Select();在该语言的早期版本中,需要以下特殊语法。
// In Visual C# 2008, you cannot access the Range, Offset, and Value // properties directly. excelApp.get_Range("A1").Value2 = "ID"; excelApp.ActiveCell.get_Offset(1, 0).Select();您不能创建自己的索引属性。该功能只支持使用现有的索引属性。
有关更多信息,请参见如何:在 COM 互操作编程中使用索引属性(C# 编程指南)。
将以下代码添加到 DisplayInExcel 的末尾,用于根据内容的需要调整列宽。
' Add the following two lines at the end of the With statement. .Columns(1).AutoFit() .Columns(2).AutoFit()excelApp.Columns[1].AutoFit(); excelApp.Columns[2].AutoFit();这些新增内容演示了 C# 2010 中的另一项新功能:将从 COM 宿主(例如 Office)返回的 Object 值按照其具有类型 dynamic 来处理。如果**“嵌入互操作类型”**设置为其默认值 True,或者,同样地,如果 /link 编译器选项引用了程序集,则此情况会自动发生。类型 dynamic 允许后期绑定(Visual Basic 中的已有功能),并可避免 Visual C# 2008 及该语言的早期版本中所需的显式强制转换。
例如,excelApp.Columns[1] 返回 Object,并且,AutoFit 是 Excel 范围 方法。如果没有 dynamic,您必须在调用方法 AutoFit 之前将 excelApp.Columns[1] 返回的对象强制转换为 Range 的实例。
// Casting is required in Visual C# 2008. ((Excel.Range)excelApp.Columns[1]).AutoFit(); // Casting is not required in Visual C# 2010. excelApp.Columns[1].AutoFit();有关嵌入互操作类型的更多信息,请参见本主题后面的“查找 PIA 引用”和“还原 PIA 依赖项”过程。有关 dynamic 的更多信息,请参见 dynamic(C# 参考)或使用类型 dynamic(C# 编程指南)。
调用 DisplayInExcel
将以下代码添加到 ThisAddIn_StartUp 方法的末尾。对 DisplayInExcel 的调用包含两个参数。第一个参数是要处理的帐户列表的名称。第二个参数是一个多行 lambda 表达式,该表达式定义要如何处理数据。每个帐户的 ID 和 balance 值显示在相邻的单元格中,如果余额小于零,则该行显示为红色。多行 lambda 表达式是 Visual Basic 2010 中的一项新功能。有关更多信息,请参见Lambda 表达式 (Visual Basic)。
DisplayInExcel(bankAccounts, Sub(account, cell) ' This multiline lambda expression sets custom ' processing rules for the bankAccounts. cell.Value = account.ID cell.Offset(0, 1).Value = account.Balance If account.Balance < 0 Then cell.Interior.Color = RGB(255, 0, 0) cell.Offset(0, 1).Interior.Color = RGB(255, 0, 0) End If End Sub)DisplayInExcel(bankAccounts, (account, cell) => // This multiline lambda expression sets custom processing rules // for the bankAccounts. { cell.Value = account.ID; cell.Offset[0, 1].Value = account.Balance; if (account.Balance < 0) { cell.Interior.Color = 255; cell.Offset[0, 1].Interior.Color = 255; } });若要运行程序,请按 F5。将出现一个 Excel 工作表,其中包含帐户中的数据。
添加 Word 文档
将以下代码添加到 ThisAddIn_StartUp 方法的末尾,以创建一个 Word 文档,其中包含指向 Excel 工作簿的链接。
Dim wordApp As New Word.Application wordApp.Visible = True wordApp.Documents.Add() wordApp.Selection.PasteSpecial(Link:=True, DisplayAsIcon:=True)var wordApp = new Word.Application(); wordApp.Visible = true; wordApp.Documents.Add(); wordApp.Selection.PasteSpecial(Link: true, DisplayAsIcon: true);此代码演示 C# 中的若干新功能:在 COM 编程中省略 ref 关键字的功能、命名参数以及可选参数。这些功能是 Visual Basic 中的已有功能。方法 PasteSpecial 具有七个形参,定义为可选的引用参数。在 Visual C# 2010 之前,您必须为这七个形参定义要用作实参的对象变量,即使您没有要传递的有意义值也是如此。利用命名实参和可选实参,您可以指定要按名称访问的形参,并仅向这些形参发送实参。在此示例中,将发送参数以指示应创建指向剪贴板上的工作簿的链接(参数 Link),并且该链接将在 Word 文档中显示为图标(参数 DisplayAsIcon)。利用 Visual C# 2010,您还可以为这些参数省略 ref 关键字。将 Visual C# 2008 中的以下代码段与 Visual C# 2010 中所需的单行进行比较:
// Call to PasteSpecial in Visual C# 2008. object iconIndex = Type.Missing; object link = true; object placement = Type.Missing; object displayAsIcon = true; object dataType = Type.Missing; object iconFileName = Type.Missing; object iconLabel = Type.Missing; wordApp.Selection.PasteSpecial(ref iconIndex, ref link, ref placement, ref displayAsIcon, ref dataType, ref iconFileName, ref iconLabel); // Call to PasteSpecial in Visual C# 2010. wordApp.Selection.PasteSpecial(Link: true, DisplayAsIcon: true);
运行应用程序
- 按 F5 运行该应用程序。Excel 将启动并显示一个表格,其中包含 bankAccounts 中的两个帐户的信息。然后,将出现一个 Word 文档,其中包含指向该 Excel 表格的链接。
清理完成的项目
- 在 Visual Studio 中,单击**“生成”菜单上的“清理解决方案”**。否则,每次在计算机上打开 Excel 时,外接程序都将运行。
查找 PIA 引用
重新运行应用程序,但是不要单击**“清理解决方案”**。
在**“开始”菜单上,单击“所有程序”。然后依次单击“Microsoft Visual Studio 2010”、“Visual Studio 工具”、“Visual Studio 命令提示(2010)”**。
在“Visual Studio 命令提示(2010)”窗口中键入 ildasm,然后按 Enter。此时将出现“IL DASM”窗口。
在 IL DASM 窗口中的**“文件”菜单上,单击“打开”。双击“Visual Studio 2010”,然后双击“项目”**。打开项目的文件夹,并查找 您的项目名称.dll 的 bin/Debug 文件夹。双击 您的项目名称.dll。一个新窗口将显示项目的特性,以及对其他模块和程序集的引用。请注意,程序集中包括了命名空间 Microsoft.Office.Interop.Excel 和 Microsoft.Office.Interop.Word。在 Visual Studio 2010 中,默认情况下编译器会将所需的类型从引用的 PIA 导入程序集中。
有关更多信息,请参见如何:查看程序集内容。
双击**“清单”**图标。此时将出现一个包含程序集列表的窗口,这些程序集包含项目所引用的项。列表中未包括 Microsoft.Office.Interop.Excel 和 Microsoft.Office.Interop.Word。由于项目所需的类型已导入到程序集中,因此无需引用 PIA。这样,部署会更加轻松。PIA 不必位于用户的计算机上,并且,由于应用程序不需要部署特定版本的 PIA,因此可将应用程序设计为与多个版本的 Office 一起使用,只要所有版本中都有必要的 API 即可。
由于不再必须要部署 PIA,因此,您可以在高级方案中创建与多个版本的 Office(包括早期版本)一起使用的应用程序。但是,只有当您的代码未使用您所使用的 Office 版本中未提供的任何 API 时,此情况才适用。由于不能总是清楚地了解特定 API 在早期版本是否可用,因此出于该原因,建议不要使用 Office 的早期版本。
说明在 Office 2003 之前,Office 未发布 PIA。因此,为 Office 2002 或早期版本生成互操作程序集的唯一方式是通过导入 COM 引用。
关闭清单窗口和程序集窗口。
还原 PIA 依赖项
在**“解决方案资源管理器”中,单击“显示所有文件”按钮。展开“引用”文件夹,并选择“Microsoft.Office.Interop.Excel”。按 F4 以显示“属性”**窗口。
在**“属性”窗口中,将“嵌入互操作类型”属性从“True”更改为“False”**。
为 Microsoft.Office.Interop.Word 重复此过程中的步骤 1 和 2。
在 C# 中,将 DisplayInExcel 方法末尾对 Autofit 的两个调用注释掉。
按 F5 验证项目是否仍然能够正常运行。
重复前面过程中的步骤 1-3 以打开程序集窗口。请注意,嵌入程序集的列表中不再有 Microsoft.Office.Interop.Word 和 Microsoft.Office.Interop.Excel。
双击**“清单”图标,并滚动浏览引用的程序集的列表。Microsoft.Office.Interop.Word 和 Microsoft.Office.Interop.Excel 均在列表中。由于应用程序引用 Excel 和 Word PIA,并且“嵌入互操作类型”属性设置为“False”**,因此两个程序集都必须存在于最终用户的计算机上。
在 Visual Studio 中,单击**“生成”菜单上的“清理解决方案”**以清理完成的项目。
请参见
任务
如何:在 COM 互操作编程中使用索引属性(C# 编程指南)
演练:嵌入 Microsoft Office 程序集中的类型信息(C# 和 Visual Basic)
演练:嵌入托管程序集中的类型(C# 和 Visual Basic)