在 Office 2010 项目中采用 C# 语言增强

Office 可视操作方法

**摘要:**C# 2010 增加了多项语言增强功能,更易于与 Office 对象模型进行交互。可使用这些新的语言功能减小 C# 代码的大小并降低其复杂性。

上次修改时间: 2015年3月9日

适用范围: Excel 2010 | Office 2010 | Open XML | PowerPoint 2010 | VBA | Word 2010

**发布时间:**2010 年 9 月

供稿人:MVP 参与者Ken Getz(该链接可能指向英文页面)MCW Technologies(该链接可能指向英文页面) | 关于作者

概述

在早期版本的 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 项目,其中已包含所有这些更改。)

  1. 在 Microsoft Visual Studio 2010 中,加载原始示例项目 WorkingWithOffice35\WorkingWithOffice.sln。

  2. 检查 Program.cs。运行应用程序并逐步执行代码。请注意,该项目包含对 Word 和 Excel 类型库的引用集,并在代码文件的顶部包含针对这两个互操作程序集的 using 语句。

  3. 请注意,GenerateChart 过程包含一个确定其是否将图表复制到 Microsoft Word 的参数。

    static void GenerateChart(bool copyToWord)
  4. 请注意,调用过程 Main 会将 true 作为参数传递给 GenerateChart 过程。如果调用代码以某种简单方式将该参数视为可选参数,同时被调用的过程假定 GenerateChart(true); 参数的值为 true(与在 Visual Basic 或 VBA 过程中一样),那么这是一个不错的做法。

  5. 在"解决方案资源管理器"窗口中,右键单击项目节点,并从上下文菜单选择"属性",然后在"属性"窗口中,将"目标框架"属性设置为".NET Framework 4 客户端配置文件"。

  6. 在"解决方案资源管理器"窗口中,右键单击项目节点并选择"添加引用"。在"添加引用"对话框中的".NET"选项卡中,选择"Microsoft.CSharp"。单击"确定"以添加引用。

  1. C# 2010 可使过程轻松接受可选参数。若要修改 GenerateChart 参数以使其可选,请修改声明以使其类似于以下代码。为该参数添加默认值可自动使其可选。

    static void GenerateChart(bool copyToWord = true)
  2. 在 Main 过程中修改对 GenerateChart 的调用,使其利用新的可选参数(假定该调用打算将 copyToWord 参数设置为 true)。

    GenerateChart();
  3. 在 GenerateChart 中检查前三行代码。这些代码行会创建一个新的 Excel 应用程序实例,将其设置为可见,并添加一个新的工作簿。

    var excel = new Excel.Application();
    excel.Visible = true;
    excel.Workbooks.Add(Type.Missing);
  4. "Workbooks.Add"方法接受一个指示要使用的模板的可选参数。早期版本的 C# 不支持传递可选参数,而 C# 2010 正确地解决了此问题。修改对 WorkBooks.Add 方法的调用,同时删除 Type.Missing 参数。这将简化代码,使其与 VBA 或 Visual Basic 代码更类似,如下面的示例所示。

    excel.Workbooks.Add();
  5. 检查后两行代码。这些代码行将当前工作表中两个单元格的值设置为"Process Name"和"Memory Usage"。请注意有关此代码的以下几点:

  6. C# 2010 支持参数化属性以便修改前两行代码,使其检索 Excel 对象的 Range 属性,并设置 Value 属性而非 Value2 属性。

    excel.Range["A1"].Value = "Process Name";
    excel.Range["B1"].Value = "Memory Usage";
  7. 检查下面的示例,该示例设置一个 LINQ 查询以检索当前占用最多内存的十个进程。由于此代码与 COM 互操作无关,因此,您可将此代码保持不变。

    var processes =
      Process.GetProcesses()
            .OrderByDescending(p => p.WorkingSet64)
            .Take(10);
  8. 下面的代码将进程列表中的值复制到工作表的单元格中。与以前一样,由于早期版本的 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++;
    }
  9. 将循环中的代码替换为下面的代码,并利用您已看到的相同的 C# 2010 功能。

    excel.Range["A" + i].Value = p.ProcessName;
    excel.Range["B" + i].Value = p.WorkingSet64;
    i++;
  10. 后两行代码会自动调整以适合两个列。请注意,此代码会将 Excel.Columns[] 强制转换为 Excel.Range。

    ((Excel.Range)excel.Columns[2]).AutoFit();
  11. 将 COM 互操作与 C# 一起使用的一个常见情况是,您将 VBA 解决方案中的代码复制到 C# 中,并将其转换为托管代码。但在本示例中并非如此。VBA 是一种更松散的类型语言,它不需要显式强制转换。在此示例中,如果您具有调用列的 AutoFit 方法的 VBA 代码,则此代码无需强制转换。但是,当您将此代码复制到 C# 中时,您需要确定对象的准确类型,以便能执行所需的强制转换。C# 2010 提供了动态类型,使您能够在运行时之前遵从类型规范。例如,您可以修改前面的代码以使用动态类型,而无需在将 VBA 代码复制到 C# 类中时确定准确的类型。虽然此步骤不是必需的步骤,但它演示了如何更轻松地将代码直接从 VBA 复制到 C# 项目中。

    ((dynamic)excel.Columns[1]).Autofit();
    ((dynamic)excel.Columns[2]).Autofit();
  12. 下面的示例检索对单元格 A1 的引用。此代码将调用 get_Range 方法(到目前为止,您已知道如何改进此代码了)。

    Excel.Range range = excel.get_Range("A1", Type.Missing);
  13. 修改代码行,并替换对 get_Range 方法的调用。

    Excel.Range range = excel.Range["A1"];
  14. 下面的示例将新图表添加到活动表中的工作簿中。Charts.Add 方法需要四个参数。即使这四个参数都是可选的,但早期版本的 C# 要求您为所有这些参数提供值。

    Excel.Chart chart = (Excel.Chart)excel.
      ActiveWorkbook.Charts.Add(
      Type.Missing, excel.ActiveSheet, Type.Missing, Type.Missing);
  15. 修改对 Charts.Add 的调用,并利用 C# 2010 的功能以使用可选参数。在此示例中,代码将接受所有默认值。另请注意,Charts.Add 方法现将返回一个动态对象。因此,不需要强制转换。

    Excel.Chart chart = excel.ActiveWorkbook.Charts.Add();
  16. 下面的示例将调用 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);
  17. C# 2010 允许您使用命名参数,以便您能在复杂的方法调用中指定小部分参数。修改代码,并修复对 get_Range 方法和 ChartWizard 方法的调用。

    // Note the use of named parameters:
    chart.ChartWizard(
      Source: range.CurrentRegion,
      Title: "Memory Usage in: " + Environment.MachineName);
  18. 下面的示例将设置图表的格式,然后将其复制到剪贴板。您无法改进此代码:

    chart.ChartStyle = 45;
    chart.CopyPicture(Excel.XlPictureAppearance.xlScreen,
      Excel.XlCopyPictureFormat.xlBitmap,
      Excel.XlPictureAppearance.xlScreen);
  1. 下面的示例将检查调用方是否需要将图表复制到 Microsoft Word 中,如果需要这样做,请创建 Microsoft Word 应用程序的新实例并使其可见。

    if (copyToWord)
    {
      var word = new Word.Application();
      word.Visible = true;
      // The following method call isn't really safe: because the variable
      // missing is passed by reference, its value could be changed.
      // To do it correctly would require creating an individual variable
      // for each parameter.
      // Code removed here…
    }
  2. 下面的示例将调用 Word.Documents.Add 方法,而 Microsoft Word 通常会按引用传递其所有参数,这就会使方法调用复杂化。早期版本的 C# 需要您传递所有参数,即使这些参数是可选的也是如此,在此示例中,您不仅必须传递所有参数,而且必须按引用传递所有参数。示例代码会以一种不安全的方式执行此操作,因为 Word.Documents.Add 方法可能会修改其引用参数之一。虽然此代码能用,但它绝对不是好的选择。为了安全起见,您必须为每个参数创建一个单独变量,并按引用将每个参数传递给 Word 方法。

    object missing = Type.Missing;
    word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
  3. 由于 C# 2010 将处理可选参数,因此,您无需为 Documents.Add 方法的可选参数传递变量。修改代码,并对其进行简化以便对所有参数使用默认值。

    word.Documents.Add();
  4. 通过调用 Selection.Paste 方法完成代码,并将剪贴板上的图表放置到 Word 文档中。无需修改此代码。

    word.Selection.Paste();
  5. 保存并运行项目,并确保其像以前一样运行,尽管它采用的是更加简单的代码。

利用 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。