在早期版本的 C# 中,编写与 Microsoft Office 应用程序交互的代码需要处理由 C# 语言和组件对象模型 (COM) 组件之间进行的交互带来的许多难题。C# 2010 增加了多项语言功能,其中包含命名参数和可选参数、对 COM 互操作的更佳支持等。
本文附带的代码示例包含一个控制台应用程序,其中包括一个过程 GenerateChart。该过程使用 COM 互操作来同时与 Microsoft Excel 和 Microsoft Word 进行交互。此代码将检索有关如何在主机上运行进程的信息,并将在 Excel 中创建一个显示有关进程和内存占用情况的信息的图表。然后,此代码会复制该图表并将其粘贴到 Microsoft Word 文档中。虽然此代码非常简单,但它演示了多项侧重于如何增强 COM 互操作编码的新 C# 语言功能。图 1 演示了在其任一版本(Microsoft .NET Framework 3.5 或 Microsoft .NET Framework 4)中运行此代码示例所获得的结果。
图 1. 代码示例将在 Microsoft Excel 中创建此图表,并将其粘贴到 Microsoft Word 中
按照这些步骤进行操作可在代码示例项目中转换 GenerateChart 过程,使其使用新的 C# 2010 功能。(您还可以查看 WorkWithOffice40 项目,其中已包含所有这些更改。)
在 Microsoft Visual Studio 2010 中,加载原始示例项目 WorkingWithOffice35\WorkingWithOffice.sln。
检查 Program.cs。运行应用程序并逐步执行代码。请注意,该项目包含对 Word 和 Excel 类型库的引用集,并在代码文件的顶部包含针对这两个互操作程序集的 using 语句。
请注意,GenerateChart 过程包含一个确定其是否将图表复制到 Microsoft Word 的参数。
static void GenerateChart(bool copyToWord)
请注意,调用过程 Main 会将 true 作为参数传递给 GenerateChart 过程。如果调用代码以某种简单方式将该参数视为可选参数,同时被调用的过程假定 GenerateChart(true); 参数的值为 true(与在 Visual Basic 或 VBA 过程中一样),那么这是一个不错的做法。
在"解决方案资源管理器"窗口中,右键单击项目节点,并从上下文菜单选择"属性",然后在"属性"窗口中,将"目标框架"属性设置为".NET Framework 4 客户端配置文件"。
在"解决方案资源管理器"窗口中,右键单击项目节点并选择"添加引用"。在"添加引用"对话框中的".NET"选项卡中,选择"Microsoft.CSharp"。单击"确定"以添加引用。
C# 2010 可使过程轻松接受可选参数。若要修改 GenerateChart 参数以使其可选,请修改声明以使其类似于以下代码。为该参数添加默认值可自动使其可选。
static void GenerateChart(bool copyToWord = true)
在 Main 过程中修改对 GenerateChart 的调用,使其利用新的可选参数(假定该调用打算将 copyToWord 参数设置为 true)。
GenerateChart();
在 GenerateChart 中检查前三行代码。这些代码行会创建一个新的 Excel 应用程序实例,将其设置为可见,并添加一个新的工作簿。
var excel = new Excel.Application();
excel.Visible = true;
excel.Workbooks.Add(Type.Missing);
"Workbooks.Add"方法接受一个指示要使用的模板的可选参数。早期版本的 C# 不支持传递可选参数,而 C# 2010 正确地解决了此问题。修改对 WorkBooks.Add 方法的调用,同时删除 Type.Missing 参数。这将简化代码,使其与 VBA 或 Visual Basic 代码更类似,如下面的示例所示。
excel.Workbooks.Add();
检查后两行代码。这些代码行将当前工作表中两个单元格的值设置为"Process Name"和"Memory Usage"。请注意有关此代码的以下几点:
C# 2010 支持参数化属性以便修改前两行代码,使其检索 Excel 对象的 Range 属性,并设置 Value 属性而非 Value2 属性。
excel.Range["A1"].Value = "Process Name";
excel.Range["B1"].Value = "Memory Usage";
检查下面的示例,该示例设置一个 LINQ 查询以检索当前占用最多内存的十个进程。由于此代码与 COM 互操作无关,因此,您可将此代码保持不变。
var processes =
Process.GetProcesses()
.OrderByDescending(p => p.WorkingSet64)
.Take(10);
下面的代码将进程列表中的值复制到工作表的单元格中。与以前一样,由于早期版本的 C# 的限制,此代码将调用 get_Range 方法并设置 Value2 属性。
int i = 2;
foreach (var p in processes)
{
excel.get_Range("A" + i, Type.Missing).Value2 = p.ProcessName;
excel.get_Range("B" + i, Type.Missing).Value2 = p.WorkingSet64;
i++;
}
将循环中的代码替换为下面的代码,并利用您已看到的相同的 C# 2010 功能。
excel.Range["A" + i].Value = p.ProcessName;
excel.Range["B" + i].Value = p.WorkingSet64;
i++;
后两行代码会自动调整以适合两个列。请注意,此代码会将 Excel.Columns[] 强制转换为 Excel.Range。
((Excel.Range)excel.Columns[2]).AutoFit();
将 COM 互操作与 C# 一起使用的一个常见情况是,您将 VBA 解决方案中的代码复制到 C# 中,并将其转换为托管代码。但在本示例中并非如此。VBA 是一种更松散的类型语言,它不需要显式强制转换。在此示例中,如果您具有调用列的 AutoFit 方法的 VBA 代码,则此代码无需强制转换。但是,当您将此代码复制到 C# 中时,您需要确定对象的准确类型,以便能执行所需的强制转换。C# 2010 提供了动态类型,使您能够在运行时之前遵从类型规范。例如,您可以修改前面的代码以使用动态类型,而无需在将 VBA 代码复制到 C# 类中时确定准确的类型。虽然此步骤不是必需的步骤,但它演示了如何更轻松地将代码直接从 VBA 复制到 C# 项目中。
((dynamic)excel.Columns[1]).Autofit();
((dynamic)excel.Columns[2]).Autofit();
下面的示例检索对单元格 A1 的引用。此代码将调用 get_Range 方法(到目前为止,您已知道如何改进此代码了)。
Excel.Range range = excel.get_Range("A1", Type.Missing);
修改代码行,并替换对 get_Range 方法的调用。
Excel.Range range = excel.Range["A1"];
下面的示例将新图表添加到活动表中的工作簿中。Charts.Add 方法需要四个参数。即使这四个参数都是可选的,但早期版本的 C# 要求您为所有这些参数提供值。
Excel.Chart chart = (Excel.Chart)excel.
ActiveWorkbook.Charts.Add(
Type.Missing, excel.ActiveSheet, Type.Missing, Type.Missing);
修改对 Charts.Add 的调用,并利用 C# 2010 的功能以使用可选参数。在此示例中,代码将接受所有默认值。另请注意,Charts.Add 方法现将返回一个动态对象。因此,不需要强制转换。
Excel.Chart chart = excel.ActiveWorkbook.Charts.Add();
下面的示例将调用 ChartWizard 方法以基于与单元格 A1 相连的数据创建一个新图表。虽然此块为 ChartRegion 方法传递了多个可选参数,但只会显式指定其中几个参数。
chart.ChartWizard(
range.CurrentRegion,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing,
"Memory Usage in: " + Environment.MachineName,
Type.Missing, Type.Missing, Type.Missing);
C# 2010 允许您使用命名参数,以便您能在复杂的方法调用中指定小部分参数。修改代码,并修复对 get_Range 方法和 ChartWizard 方法的调用。
// Note the use of named parameters:
chart.ChartWizard(
Source: range.CurrentRegion,
Title: "Memory Usage in: " + Environment.MachineName);
下面的示例将设置图表的格式,然后将其复制到剪贴板。您无法改进此代码:
chart.ChartStyle = 45;
chart.CopyPicture(Excel.XlPictureAppearance.xlScreen,
Excel.XlCopyPictureFormat.xlBitmap,
Excel.XlPictureAppearance.xlScreen);
利用 C# 2010,可以比以前更轻松地将代码直接从 VBA 解决方案复制并粘贴到 C# 中。当然,您必须设置对适当的类型库(在此示例中为 Microsoft Word 和 Microsoft Excel)的引用,但在 C# 2010 中提供了新功能的情况下,您可经常将代码直接从 VBA 复制到 C# 项目中,并仅添加分号来分隔代码行。
通过使用 C# 2010 的新功能来扩展其适用性以便与 COM 互操作进行交互。您可以执行以下操作:使用可选参数创建您自己的方法,按名称传递参数并使用可选参数,创建您自己的动态类并与动态语言(例如,Iron Python 和 Ruby)进行交互。花时间查看 C# 中的新的语言功能。您将发现,可比以前更轻松地创建 COM 互操作代码,并可在纯 C# 解决方案中使用新功能。(所有这些功能都包含在 Visual Basic 中。其中大多数功能自发行第一个语言版本后便可用。最新版本的 Visual Basic 还增加了对动态语言的支持。) |
观看视频(该链接可能指向英文页面)
获取代码(该链接可能指向英文页面)
视频时长:00:09:25
文件大小:11.2 MB WMV
关于作者
Ken Getz (MVP) 是一名开发人员、作家和培训师,他是 MCW Technologies, LLC(该链接可能指向英文页面) 的高级顾问。过去十五年内,他撰写了几百篇技术文章,并且是 AppDev(该链接可能指向英文页面) 的主要课件作者。Ken 与其他人合著了多本面向开发人员的技术书籍,其中包括以下畅销书:ASP.NET Developer's Jumpstart(《ASP.NET 开发人员入门》)、Access Developer's Handbook(《Access 开发人员手册》)系列书籍和 VBA Developer's Handbook(《VBA 开发人员手册》)系列书籍。Ken 是 INETA Speakers Bureau 的成员,他定期在各种行业活动中发表演讲,其中包括 1105 Media's VSLive 和 Microsoft Tech-Ed。 |