Visual Studio 2010:Office 编程

概述

Microsoft Office 为组织提供了一个最终用户非常熟悉的环境来快速创建业务应用程序。构建 Office 业务应用程序为组织提供了利用以下内容的大量机会:编辑客户关系管理 (CRM) 系统、将从业务线应用程序提取的数据前置、托管商业智能报告,以及很多其他可能性。

尽管 Office 开发为组织提供了很多有价值的机会,但是之前它也为这些应用程序的开发和部署提出了一些挑战。早期的托管语言版本也推动了使用 Office 创建应用程序的方式。 

调用大量的 Office API 方法通常很难,因为其中包含很多参数,而且大多数参数都无用。Visual Basic 的可选参数功能简化了这一操作,但是使用 C# 语言的开发人员将不得不编写大量无用的初始化表达式或空语句,以填写所需的方法签名参数。如果您使用的是 Visual Basic,您将无法使用类似于 C# 3.0 的 lambda 的功能来在调用代理时提供内联方法。

在本实验中,您将看到 Visual Studio 2010、 C# 4.0 和 Visual Basic 10 中的新功能如何消除上述段落中提到的问题。此外,您还将看到其他一些强大功能,这些功能加速了其他 Office 要素的开发。

目标

在本次动手实验中,您将学习如何:

•              学习新语言功能如何加速业务实体的创建

•              探索一些新的语言功能,这些功能使业务实体与 Excel 的交互变得更容易

•              利用支持在 Office 程序之间进行快速交互的新语言功能

•              了解新的构建过程如何简化向最终用户部署 Office 应用程序的过程

               

系统要求

您必须拥有以下内容才能完成本实验:

•             Microsoft Visual Studio 2010 Beta 2

•             .Net Framework 4

•             Microsoft Excel 2007

•             Microsoft Word 2007

               

安装

使用 Configuration Wizard 验证本实验的所有先决条件。要确保正确配置所有内容,请按照以下步骤进行。

注意:要执行安装步骤,您需要使用管理员权限在命令行窗口中运行脚本。

1.            如果之前没有执行,运行 Training Kit 的 Configuration Wizard。为此,运行位于 %TrainingKitInstallationFolder%\Labs\Dev10Office\Setup 文件夹下的 CheckDependencies.cmd 脚本。安装先决条件中没有安装的软件(如有必要请重新扫描),并完成向导。

注意:为了方便,本实验管理的许多代码都可用于 Visual Studio 代码片段。CheckDependencies.cmd 文件启动 Visual Studio 安装程序文件安装该代码片段。

               

练习

本次动手实验由以下练习组成:

1.            创建一个帐户类集合并在 Microsoft Excel 中显示帐户信息

2.            将 Microsoft Excel 工作表嵌入 Microsoft Word 文档中

3.            调整 VS 项目文件,以支持在不使用 PIA 的情况下部署程序

               

完成本实验的估计时间:60 分钟。

               

下一步

练习 1:创建一个业务实体集合并将其值插入 Excel 工作表中

               

练习 1:创建一个业务实体集合并将其值插入 Excel 工作表中

业务实体是一种常用模式,它通过应用程序或系统承载数据。业务实体可能反映一个银行帐户(显示帐户结余和帐户持有人),或者可能反映放置了很多东西的购物车,其中每项都是它自己的业务实体。

在本练习中,您将学习如何创建业务实体集合,并将这些实体的值写入 Excel 工作表中。在本练习中,您还将学习 C# 4.0 和 Visual Basic 10 中新的语言功能,这些新功能大大加快了业务实体的创建速度。

注意:要验证每个步骤是否正确执行,建议在每次任务结束时生成解决方案。

任务 1 –创建一个新控制台应用程序并引用 Microsoft Office 互操作程序集

在本任务中,您将创建一个新控制台应用程序并将其添加到进行 Office 开发所需的程序集。

1.            从 Start | All Programs | Microsoft Visual Studio 2010 | Microsoft Visual Studio 2010 打开 Microsoft Visual Studio 2010。

2.            在 Microsoft Visual Studio 初始页面, 单击 New Project 图标。

注意:本实验将使用 C# 和 Visual Basic 两种语言进行展示。您可以使用任何您熟悉的语言。在实验过程中,将指出 Visual Studo 2010 和每种语言的新功能。

3.            在 C# 或 Visual Basic 项目模板列表中,选择 Windows | Console Application.

4.            在Name字段中,输入“OfficeApplication”

5.            在右上角,确保选择了 .NET Framework 4.0 版本。

6.            接受默认的位置和解决方案名称。单击 OK 按钮。该解决方案将使用一个控制台应用程序项目进行创建。

7.            右键单击 OfficeApplication 项目节点并选择 Add Reference…。

8.            在Add Reference 对话框的 .NET选项卡下,选择 Microsoft.Office.Interop.Excel。按住 CTRL 键并单击 Microsoft.Office.Interop.Word。单击 OK 按钮。

注意:由于本实验针对的是 Office 2007,所以要确保在添加引用时选择了版本 12.0.0.0。

完成时,控制台应用程序的引用列表应如下所示:

 

图 1

Office 开发引用

               

任务 2 –创建业务实体集合

在本任务中,您将创建一个将预先填充数据的业务实体集合。预先填充用于模拟从单独的源加载带有数据的实体。在此我们将重点介绍数据访问。

首先从创建单独实体开始。

1.            在 Solution Explorer 中,右键单击 OfficeApplication 项目的节点,并从菜单中选择 Add… | Class 。

2.            将出现 Add New Item 对话框,其中包含已选中的 Class 模板。将名称更改为 Account.cs (C#) 或 Account.vb (Visual Basic),单击 Add 按钮。

a.            如果使用 C# 语言进行本实验,将 Account 类的定义更改为 public,如下所示:

C#

public class Account

{

}

3.            为 Account 添加公共属性 ID (integer)、Balance (double) 和 AccountHolder (string),如下所示:

(代码片段– Office 编程实验 - 练习 1 Account 属性 CSharp)

C#

public class Account

{

    public int ID { get; set; }

    public double Balance { get; set; }

    public string AccountHolder { get; set; }

}

(代码片段– Office 编程实验 - 练习 1 Account 属性 VB)

Visual Basic

Public Class Account

    Property ID As Integer

    Property Balance As Double

    Property AccountHolder As String

End Class

注意:Visual Basic 有一项新功能,那就是无需声明一个存储值的单独字段就可以声明属性。这种自动实现属性的工作方式就好象开发人员声明了一个私有字段来存储数据并实现了简单的“getter”和“setter”方法。它们的调用方式与传统属性的调用方式相同。如果属性访问需要更可靠的逻辑,那么仍然可以创建在私有字段中存储数据的传统属性。VS 2008 相应的 Visual Basic 代码如下所示:

Visual Basic

' This is the old style using backing variables instead of

' auto-implemented properties

Public Class Account

Private _id As Integer

Private _balance As Double

Private _accountHolder As String

Property ID() As Integer

Get

Return _id

End Get

Set(ByVal value As Integer)

_id = value

End Set

End Property

Property Balance() As Double

Get

Return _balance

End Get

Set(ByVal value As Double)

_balance = value

End Set

End Property

Property AccountHolder() As String

Get

Return _accountHolder

End Get

Set(ByVal value As String)

_accountHolder = value

End Set

End Property

End Class

4.            Account 类表示您的单个实体类型。通常,应用程序会创建这些实体集合中的某些实体,并使用一些数据填充这些实体。为了保持本实验简洁明了,将通过在创建列表时将值推入各个对象来填充列表。在 Module1.vb (VB) 或 Program.cs (C#) 文件中,创建一个名为 CreateAccountList 的新方法,如以下代码所示:

(代码片段– Office 编程实验 - 练习 1 CreateAccountList VB)

Visual Basic

Private Function CreateAccountList() As List(Of Account)

    Dim checkAccounts As New List(Of Account) From {

        New Account With {

            .ID = 1,

            .Balance = 285.93,

            .AccountHolder = "John Doe"

        },

        New Account With {

            .ID = 2,

            .Balance = 2349.23,

            .AccountHolder = "Richard Roe"

        },

        New Account With {

                     .ID = 3,

                     .Balance = -39.46,

            .AccountHolder = "I Dunoe"

        }

    }

    Return checkAccounts

End Function

注意:上述代码强调了 Visual Basic 的另一项新功能:集合初始化程序。这使开发人员能够节省大量时间,因为他们可以直接在声明列表时初始化列表的内容。无需实例化列表,然后逐个“更新”更新各项将其添加到列表中。

(代码片段– Office 编程实验 - 练习 1 CreateAccountList CSharp)

C#

private static List<Account> CreateAccountList()

{

    var checkAccounts = new List<Account> {

        new Account{

            ID = 1,

            Balance = 285.93,

            AccountHolder = "John Doe"

        },

        new Account{

            ID = 2,

            Balance = 2349.23,

            AccountHolder = "Richard Roe"

        },

        new Account{

            ID = 3,

            Balance = -39.46,

            AccountHolder = "I Dunoe"

        }

    };

    return checkAccounts;

}

5.            从 Module1.vb (VB) 或 Program.cs (C#) 文件中的 Main 方法调用 CreateAccountList 方法,如下所示:

Visual Basic

Sub Main()

    Dim checkAccounts = CreateAccountList()

End Sub

C#

static void Main(string[] args)

{

    var checkAccounts = CreateAccountList();

}

               

任务 3 –创建 Excel 工作簿并使用来自业务实体的数据填充它

在本任务中,您将创建一个新 Excel 工作簿。然后您可以遍历业务对象集合并将数据插入 Excel 工作簿中。最后您将格式化工作表。

1.            第一步是使用 Imports (VB) 或 using (C#) 语句导入 Office 命名空间。在 Module1.vb (VB) 或 Program.cs (C#) 文件的顶部输入以下代码:

(代码片段– Office 编程实验 - 练习 1 Namespaces VB)

Visual Basic

Imports Microsoft.Office.Interop

Imports System.Runtime.CompilerServices

(代码片段– Office 编程实验 - 练习 1 Namespaces CSharp)

C#

using Microsoft.Office.Interop;

using Excel = Microsoft.Office.Interop.Excel;

using Word = Microsoft.Office.Interop.Word;

2.            将数据插入 Excel 的代码作为 Extension 方法实现。

该(和所有)扩展方法的第一个参数表示该方法(在帐户列表中)所操作的类型。第二个参数 (DisplayFunc) 是一个类型为 delegate 的 Action。Action 代理可以接受任意多个参数,但总是返回 void。

该代码块创建了一个具有工作簿的新 Excel 应用程序,将一些标题文本插入工作簿中,调用一个帮助程序方法来显示 Account 对象的值,然后将每列设置为 AutoFit 模式,以更好地显示每列的值。

在 Module1.vb (VB) 或 Program.cs (C#) 中的 Main 方法后输入以下代码:

(代码片段– Office 编程实验 - 练习 1 DisplayInExcel VB)

Visual Basic

<Extension()>

Sub DisplayInExcel(ByVal accounts As IEnumerable(Of Account), ByVal DisplayFunc As Action(Of Account, Excel.Range))

    With New Excel.Application

        .Workbooks.Add()

        .Visible = True

        .Range("A1").Value = "ID"

        .Range("B1").Value = "Balance"

        .Range("C1").Value = "Account Holder"

        .Range("A2").Select()

        For Each ac In accounts

            DisplayFunc(ac, .ActiveCell)

            .ActiveCell.Offset(1, 0).Select()

        Next

               

        .Columns(1).AutoFit()

        .Columns(2).AutoFit()

        .Columns(3).AutoFit()

    End With

End Sub

注意:在 C# 中,有必要将 Program.cs 中的 Program 类声明更改为 static。

(代码片段– Office 编程实验 - 练习 1 DisplayInExcel CSharp)

C#

static void DisplayInExcel(this IEnumerable<Account> accounts,

                          Action<Account, Excel.Range> DisplayFunc)

{

    var x1 = new Excel.Application();

//see the Note below

    x1.Workbooks.Add();

    x1.Visible = true;

    x1.get_Range("A1").Value2 = "ID";

    x1.get_Range("B1").Value2 = "Balance";

    x1.get_Range("C1").Value2 = "Account Holder";

    x1.get_Range("A2").Select();

    foreach (var ac in accounts)

    {

        DisplayFunc(ac, x1.ActiveCell);

        x1.ActiveCell.get_Offset(1, 0).Select();

    }

     ((Excel.Range)x1.Columns[1]).AutoFit();

     ((Excel.Range)x1.Columns[2]).AutoFit();

     ((Excel.Range)x1.Columns[3]).AutoFit();

}

注意:语句 x1.Workbooks.Add(); 反映了 .NET Framework 4.0 和 C# 4.0 中的一个重要变化:可选参数。Microsoft.Office.Interop.Excel.Workbook COM 互操作程序集的早期版本需要传入一个参数。此外,C# 的早期版本不支持可选参数,而 Visual Basic 开发人员多年来都偏爱使用可选参数。之前,该语句显示为 x1.Workbooks.Add(Missing.Value);.NET Framework 4.0 中新的互操作程序集与 C# 4.0 对可选参数的全新支持结合使用,可以使您的语法更简洁、更清晰。

3.            下一步是从程序的 Main 方法调用扩展方法。将以下代码添加到 Main 方法的底部:

(代码片段– Office 编程实验 - 练习 1 DisplayInExcel 调用 VB)

Visual Basic

checkAccounts.DisplayInExcel(Sub(account, cell)

            cell.Value2 = account.ID

            cell.Offset(0, 1).Value2 = account.Balance

            cell.Offset(0, 2).Value2 = account.AccountHolder

            If account.Balance < 0 Then

                cell.Interior.Color = RGB(255, 0, 0)

                cell.Offset(0, 1).Interior.Color = RGB(255, 0, 0)

                cell.Offset(0, 2).Interior.Color = RGB(255, 0, 0)

            End If

        End Sub)

注意:这里您看到了 Visual Basic 的另一个新功能:语句 lambda。语句 lambda 是一个匿名代码块,它与变量类似,可以将其用作方法的参数,正如本例所示。lambda 的语法是“声明”一系列参数,在本例中是 account 和 cell,然后提供该 lambda 的逻辑。使用语句 lambdas 函数或 sub 时,不需要名称但要推理参数类型。

(代码片段– Office 编程实验 - 练习 1 DisplayInExcel 调用 CSharp)

C#

checkAccounts.DisplayInExcel((account, cell) =>

        {

            cell.Value2 = account.ID;

            cell.get_Offset(0, 1).Value2 = account.Balance;

            cell.get_Offset(0, 2).Value2 = account.AccountHolder;

            if (account.Balance < 0)

            {

                cell.Interior.Color = 255;

                cell.get_Offset(0, 1).Interior.Color = 255;

                cell.get_Offset(0, 2).Interior.Color = 255;

            }

        });

DisplayInExcel 扩展方法接受一个参数,Action 代理接受两个参数。Action 代理的参数可以是 Account 对象的实例,也可以是 Excel 工作表单元格的实例。扩展方法实际上是一个功能单位,它将被 DisplayInExcel 函数主体中的 for each 循环中的每个 Account 调用。

DisplayInExcel 函数包含创建和执行 Excel 工作簿的设置的逻辑。您所提供的代理包含从 Account 对象获取单个值并将其放在 Excel 工作表中的逻辑。

               

下一步

练习 1:验证

               

练习 1:验证

在本验证中,您将运行控制台应用程序,并可以看到,打开了 Excel 工作表并且您的帐户数据被填充到工作表中。

1.            在 Visual Studio 中,按 F5 键以调试模式运行应用程序。

2.            可以看到,应用程序启动了一个 Microsoft Excel 实例并将您的数据插入到第一个工作表中:

 

图 2

Excel 工作表中的帐户数据

注意:注意,列已设置为根据内容调整列宽。此外还要注意, 根据传入到 DisplayInExcel 函数的代理的 for each 循环的逻辑,有负债的帐户背景颜色为红色。

3.            关闭 Excel。不要保存任何更改。

               

下一步

练习 2:将 Excel 工作表嵌入 Microsoft Word 中

               

练习 2:将 Excel 工作表嵌入 Microsoft Word 中

在本练习中,将把您的 Excel 工作表嵌入到 Microsoft Word 文档中。本练习还将向 C# 开发人员介绍可选参数。

注意:要验证每个步骤是否正确执行,建议在每次任务结束时生成解决方案。

任务 1 –将 Excel 工作表嵌入到新 Microsoft Word 文档中

1.            从 Start | All Programs | Microsoft Visual Studio 2010 | Microsoft Visual Studio 2010 打开 Microsoft Visual Studio 2010。

2.            打开 OfficeApplication.sln 解决方案文件。默认情况下,该文件位于以下文件夹:%TrainingKitInstallFolder%\Labs\Dev10Office\Source\Ex02-EmbeddingWorksheet\Begin\,并选择您喜欢的语言。您也可以继续使用上一个练习完成时获得的解决方案。

3.            复制 Excel 工作表,以将其粘贴到 Word 文档中。Copy() 方法可以完成此操作。将以下代码添加到 DisplayInExcel 方法(在 Visual Basic 方法中,该命令需要位于 With 块中)的末尾:

Visual Basic

.Range("A1:C4").Copy()

C#

x1.get_Range("A1:C4").Copy();

4.            将工作表粘贴到剪贴板后,您需要创建一个 Word 文档并将工作表粘贴到该文档中。在 Module1.vb (VB) 或 Program.cs (C#) 文件中,创建一个名为 EmbedInWordDocument 的新方法,如以下代码所示:

(代码片段– Office 编程实验 - 练习 2 EmbedInWordDocument VB)

Visual Basic

private bool LoadDictionaries()

    Dim word As New Word.Application

    word.Visible = True

    word.Documents.Add()

    word.Selection.PasteSpecial(Link:=True, DisplayAsIcon:=False)

End Sub

(代码片段– Office 编程实验 - 练习 2 EmbedInWordDocument CSharp)

C#

private static void EmbedInWordDocument()

{

    var word = new Word.Application();

    word.Visible = true;

    word.Documents.Add();

    word.Selection.PasteSpecial(Link:true, DisplayAsIcon:false);

}

注意:C# 开发人员将在调用 PasteSpecial 的过程中发现 C# 4.0 的一项新功能:可选参数的使用。PasteSpecial 实际上有 7 个参数。在大多数情况下,您不需要提供这些参数的值,因为默认值已足够。在 C# 的早期版本中,这些值仍然需要提供,即使提供的值为 System.Reflection.Missing.Value 类型(这将导致调用 PasteSpecial,如下所示):

C#

object iconIndex = System.Reflection.Missing.Value;

object link = true;

object placement = System.Reflection.Missing.Value;

object displayAsIcon = false;

object dataType = System.Reflection.Missing.Value;

object iconFileName = System.Reflection.Missing.Value;

object iconLabel = System.Reflection.Missing.Value;

word.Selection.PasteSpecial(ref iconIndex,

                ref link,

                ref placement,

                ref displayAsIcon,

                ref dataType,

                ref iconFileName,

                ref iconLabel);

注意:C# 开发人员还会注意到,即使 PasteSpecial 的参数仍然被引用,也没有必要使用 ref 关键字说明这一点。

5.            从 Module1.vb (VB) 或 Program.cs (C#) 文件的 Main 方法调用 EmbedInWordDocument 方法,如下所示:

Visual Basic

Sub Main()

Dim checkAccounts = CreateAccountList()

checkAccounts.DisplayInExcel(Sub(account, cell)

cell.Value2 = account.ID

cell.Offset(0, 1).Value2 = account.Balance

cell.Offset(0, 2).Value2 = account.AccountHolder

If account.Balance < 0 Then

cell.Interior.Color = RGB(255, 0, 0)

cell.Offset(0, 1).Interior.Color = RGB(255, 0, 0)

cell.Offset(0, 2).Interior.Color = RGB(255, 0, 0)

End If

End Sub)

    EmbedInWordDocument()

End Sub

C#

static void Main(string[] args)

{

var checkAccounts = CreateAccountList();

checkAccounts.DisplayInExcel((account, cell) =>

    {

cell.Value2 = account.ID;

cell.get_Offset(0, 1).Value2 = account.Balance;

cell.get_Offset(0, 2).Value2 = account.AccountHolder;

if (account.Balance < 0)

        {

cell.Interior.Color = 255;

cell.get_Offset(0, 1).Interior.Color = 255;

cell.get_Offset(0, 2).Interior.Color = 255;

        }

    });

    EmbedInWordDocument();

}

               

下一步

练习 2:验证

               

练习 2:验证

在本验证中,您将运行控制台应用程序并可以看到,除了应用程序在上一个验证中执行的活动外,您的 Excel 工作表也嵌入到了 Microsoft Word 应用程序中。

1.            在 Visual Studio 中,按 F5 键以调试模式运行应用程序。

2.            可以看到,和之前一样,应用程序启动了 Microsoft Excel 的一个实例并将您的数据插入到第一个工作表中。

3.            创建了 Excel 工作表后,应用程序将会在 Microsoft Word 的一个实例中启动并将您的数据插入到文档中:

 

图 3

Word 文档中的帐户数据

4.            关闭 Excel 和 Word。不要保存任何更改。

               

下一步

练习 3:从应用程序移除 PIA 依赖关系

               

练习 3:从应用程序移除 PIA 依赖关系

Office 编程功能依赖于 Office PIA 类型来与 Office 套件中的各种应用程序进行交互。过去,由于多种原因,这极大地影响了自定义 Office 应用程序的部署。第一,不同版本的 Ofice 使用不同版本的 PIA,所以管理程序集变得很复杂。第二,IT 人员必须确定部署策略,确保所需的 PIA 资源在其支持库中可用。另外,部署应用程序的 PIA 会导致安装程序较大,安装了不需要的无用功能。

注意:主互操作程序集(PIA)是所有 .NET framework 应用程序与 COM 组件进行交互的关键部分。常规互操作程序集用于描述 COM 类型,支持在编译时将托管代码与 COM 类型绑定。互操作程序集还有助于 CLR 了解在运行时如何封送这些 COM 类型。主互操作程序集与常规互操作程序集的不同之处在于,它是所有类型描述的“正式”所有者,并由供应商签署以确保其有效性。

Visual Studio 2010 中的开发通过从应用程序清除 PIA 依赖关系减轻了这些负担。清除了依赖关系后,编译器将直接从 PIA 导入应用程序所需的任何类型;您只需部署应用程序,并了解您所需的所有 PIA 是否都包含在您的应用程序集中。

任务 1 –检查 PIA 依赖关系是否已被默认清除

在 Visual Studio 2010 中,默认已清除了 PIA 依赖关系,要验证这一点:

1.            从 Start | All Programs | Microsoft Visual Studio 2010 | Microsoft Visual Studio 2010 打开 Microsoft Visual Studio 2010。

2.            打开 OfficeApplication.sln 解决方案文件。默认情况下,该文件位于以下文件夹:%TrainingKitInstallFolder%\Labs\Dev10Office\Source\RemovingPIA\Begin\,并选择您喜欢的语言。您也可以继续使用上一个练习完成时获得的解决方案。

3.            展开项目的 References。

4.            右键单击项目引用中的 Microsoft.Office.Interop.Excel,并选择 Properties。

5.            注意,Embed Interop Types 的值设置为 True。

6.            右键单击项目引用中的 Microsoft.Office.Interop.Word,并选择 Properties。

7.            注意,Embed Interop Types 的值设置为 True。

下一步

总结

               

总结

在本实验中,您看到了使用 Office 创建自定义应用程序的简单性。您使用了新的语言功能,如 Visual Basic 新的自动属性和集合初始化程序,这些新功能使您能够快速构建类和方法。 

对于其他语言功能,您还看到了 C# 4.0 的可选参数,并了解了该功能如何让使用 Office 的 PIA 变得更简洁且不易出错。此外,您还学习了 Visual Basic 的多行 lambda,以及语句 lambda 如何使您简洁地将代理变为合适的语句。

最后,您还学习了如何将互操作类型嵌入 Office 业务应用程序中,以显著减轻部署 Office 应用程序的负担。这是对以前的 Office 开发环境的极大改进,在以前的开发环境中,您不得不辛苦地处理多个不同版本的依赖关系。

Visual Studio 2010 的最新版本在工具、平台和语言方面的所有这些更新都会提高您创建强大、灵活的 Office 业务应用程序的能力。