首页.Net专区C#VSTO
 
使用 Visual Studio Tools For Office 中的数据绑定为文档注入新活力
MSDN 2007年9月28日
 

本文讨论:

定义 Office 文档的数据源

创建数据绑定文档

了解数据集、适配器和源

绑定到代理对象

本文使用下列技术:
Visual Studio 2005 Tools for Microsoft Office System

*
本页内容
定义数据源 定义数据源
数据绑定文档 数据绑定文档
数据集、适配器和源 数据集、适配器和源
安全性最佳做法 安全性最佳做法
DataSets DataSets
脱机策略 脱机策略
类型化和非类型化数据集 类型化和非类型化数据集
适配器 适配器
将绑定源用作代理 将绑定源用作代理
数据绑定控件 数据绑定控件
特别注意事项 特别注意事项
小结 小结

Microsoft Visual Studio 2005 Tools for Microsoft Office System 为 Visual Studio® 环境中的 Office 开发提供一个强大的新工具集。Visual Studio Tools for Office 最重要的新功能之一是能够创建数据绑定到数据库、Web 服务或对象的文档。Excel® 工作簿的元素(在 Visual Studio Tools for Office 中称为宿主控件)- 如区域、列表对象或 Microsoft® Word 文档中的书签,可以使用创建基于 Windows® 窗体的应用程序时所使用的工具和语法进行数据绑定。还可以使用 Visual Studio Tools for Office 将数据绑定的 Windows 窗体控件添加到工作簿或文档。

使用 Visual Studio Tools for Office 设计器创建无修饰的、数据绑定的自定义文档不需要编码,但需要许多鼠标单击操作。首先,我们要告诉 Visual Studio 使用哪一个数据源(在本例中,是 Office 随附的 Northwind 示例数据库),然后将一些数据绑定控件拖放到电子表格上。

定义数据源

我们先启动 Visual Studio,新建一个 Excel 项目。依次选择 File、New Project,然后转到 Visual C#® 或 Visual Basic® 下的 Office 文件夹,选择 Excel Workbook 项目。

从 Visual Studio Data 菜单中,选择 Show Data Sources,显示 Data Sources 窗格。单击 Add New Data Source 启动 Data Source Configuration Wizard(参见图 1。)

选择 Database 并单击 Next。然后单击 New Connection。将出现第二个向导,其中列出各种数据源选项,例如 Microsoft Access Database File、Microsoft ODBC Data Source 和 Microsoft SQL Server®


图 1 启动 Data Source Configuration Wizard

选择 Microsoft Access Database File 并单击 Continue,转到 Connection 对话框。Northwind 数据库文件通常位于 \Program Files\Microsoft Office\Office11\Samples 目录中。单击 Browse 找到 Northwind 数据库。由于没有对该数据库文件强制安全性,因此将使用默认的用户名 (Admin) 和密码(空白)- 在具有安全设置的数据库的实际应用程序中,使用空白的管理员密码十分糟糕。单击 OK 关闭 Connection Wizard,继续执行 Data Source Wizard。

当单击 Next 时,Visual Studio 会通知您将创建一个到本地数据库文件的连接,该连接不是当前项目的一部分。如果您希望该项目拥有自己的数据库副本而不是修改原始数据库,则可以选择这样做,Visual Studio 将自动更新连接以指向新位置。在第一个示例中,不需要复制数据库,因此单击 No。

正如您看到的那样,您刚刚创建的有关数据库连接的所有信息都保存在一个连接字符串中。出于简便和安全方面的考虑,将该连接字符串保存在配置文件中(而不是将它硬编码到程序中)是个好方法。


图 2 选择表


我们正在连接的数据库可能具有许多查询、表,表中可能有许多列等。为了管理这种复杂性,Visual Studio 允许您选择将在 Visual Studio 中显示数据库的哪些部分。我们选择整个 Suppliers 表以及 Products 表的 ProductName、SupplierID、QuantityPerUnit 和 UnitPrice 列(参见图 2)。最后,单击 Finish 退出向导。

数据绑定文档

现在,Data Sources 窗口包含一个 NorthwindDataSet 项。展开树视图中的节点。现在出现了几个有趣的事情。首先,Visual Studio 从数据库中发现 Products 表与 Suppliers 表存在某种关系;一方面 Products 表本身作为一个表显示,另一方面它又作为 Suppliers 表的子节点显示。这将允许我们更轻松地创建主-从视图。

其次,请注意,列的图标具有"命名区域"图标,这表明如果您将图标拖放到电子表格上,将得到该列的数据绑定命名区域。列默认为命名区域,整个表默认为列表对象,但您可以通过单击项并从下拉列表中选择来选择其他控件。Visual Studio Tools for Office 的另一个强大功能是,您实际上可以将 Windows 窗体控件(如组合框)放到 Word 或 Excel 文档中,并数据绑定到文档中的 Windows 窗体控件。例如,假设您要将组合框绑定到 CompanyName。您可以从下拉列表中选择 ComboBox 作为要用于 CompanyName 的控件,如图 3 所示。


图 3 选择控件类型


将 CompanyName(作为组合框)、ContactName(作为命名区域)和整个 Products 表拖到电子表格上。使用在树视图中作为 Suppliers 表子节点的 Products 表,您将得到一个很好的主-从视图。

许多内容神奇地出现在 Excel 设计器下面的组件栏中:一个 DataSet、两个绑定源以及两个表适配器。稍后,我们将详细讨论这些组件。现在,只需编译并运行应用程序。无需编写任何代码,即可获得 Excel 电子表格上数据绑定的主-从视图。当从组合框中选择不同项时,命名区域和列表对象会自动更新(参见图 4)。


图 4 数据绑定的主-从电子表格


我们可以使用书签(而不是命名区域)和 DataGrid(而不是 Excel 列表对象)在 Word 中创建类似的数据绑定文档。新建一个 Word 文档项目,再次将 Northwind 数据库作为数据源添加到 Data Sources 窗格中。Visual Studio 应该记得上次的连接字符串,因此您将不需要再次配置它。遗憾的是,在这个版本的 Visual Studio Tools for Office 中,您无法像绑定 Excel 列表对象那样将数据表绑定到 Word 表。


图 5 运行时的主-从视图


在我们生成并运行自定义的 Word 文档后,就得到了一个在 Word 中运行的数据表的主-从视图,这同样不需要编写任何代码(参见图 5)。

数据集、适配器和源

既然您已经看到了两个不需要编写代码的示例,下面我们来看一下内部构造,了解数据绑定实际上是如何工作的。Visual Studio Tools for Office 使用的数据绑定模型与 Windows 窗体使用的模型几乎完全相同。几个角色负责数据绑定工作,其中许多角色可以在组件栏或设计界面上看到:

后端数据源(如 Microsoft Access 数据库、远程 SQL Server 数据库、Web 服务或其他一些数据存储和检索系统)是数据的最终位置。

DataSet 提供后端数据源某部分的脱机本地缓存。

适配器将 DataSet 连接到后端数据源,这样既可以用后端源填充 DataSet,又可以用任何更改来更新后端。每个表通常有一个适配器,这就是前面的示例中有两个适配器的原因。

绑定源充当用户界面控件和 DataSet 之间的中间方。稍后我们会讨论,尽管可以将控件直接绑定到 DataSet,但使用专门的绑定源对象通常更方便。

数据绑定控件提供一个允许用户读取或写入数据的用户界面元素。使用 Visual Studio Tools for Office,Word 和 Excel 文档中的某些内置元素(如 Word 书签和 Excel 区域)可以进行数据绑定。Windows 窗体控件还可以添加到 Word 文档或 Excel 电子表格,以及进行数据绑定。

在 Visual Studio Tools for Office 项目中,后端数据源由传递给适配器的连接字符串表示;所有其他内容由自定义宿主项(工作簿或文档)类的成员表示。

安全性最佳做法

您在 Connection Wizard 中可能已经注意到,连接到后端数据源所需的所有信息都存储在向导生成的一个连接字符串中。通常,该字符串如下所示:

Server=MyDataServer;Database=Customers;Integrated Security=true;

即,它说明数据库的位置、名称以及应该如何验证用户。所有这些都是潜在的敏感信息。将连接字符串嵌入程序时应谨慎操作。请记住,即使没有源代码,也很容易指出哪些字符串嵌入到托管应用程序中。这尤其适用于直接嵌入了类似以下内容的连接字符串(而没有使用集成到 Windows NT® 中的安全性):

UserID=eric;Password=BigSecret123 

而且,如果数据库连接信息经常变化,将嵌入字符串硬编码到源代码中则使开发人员、测试人员、最终用户和数据库管理员难以更新应用程序。正如前面讨论的那样,Visual Studio 允许将连接字符串嵌入配置文件。为先前示例自动生成的配置文件类似以下内容:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections/>
  <connectionStrings>
    <add name=
      "ExcelWorkbook11.Properties.Settings.NorthwindConnectionString"
      connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data 
      Source="C:\Program Files\Microsoft
      Office\OFFICE11\SAMPLES\Northwind.mdb""
      providerName="System.Data.OleDb" />
  </connectionStrings>
</configuration>

使用最低权限原则仍然是一个好方法。这是安全设计的基本原则之一:仅赋予用户完成任务所需的权限 - 不多,也不少。例如,如果用户需要能够从数据库中读取,但不需要写入,则不要指定对用户赋予数据库管理员权限的连接字符串。相反,选择一个指定具有只读权限的用户名和密码的连接字符串。这样,如果泄漏了用户名和密码,攻击者至少不会从中获得管理员权限。

最好是根本不使用存储的用户 ID 和密码;某些数据库使用集成的 Windows 身份验证,因此登录用户可以无缝使用已验证的凭据。或者,如果数据库系统需要用户名和密码,则让用户键入而不是存储它们。在我们稍后讨论适配器时您将看到,可以先手动更改适配器使用的连接字符串,然后再填充 DataSet。这样,您可以要求用户键入用户 ID 和密码,然后根据该信息生成新的连接字符串。

DataSets

通常,Visual Studio Tools for Office 数据模型和 ADO.NET 的基础是 DataSet。我们应该通过描述执行数据访问的旧方法来解释 DataSets 存在的原因。回到二十世纪,您通常通过"ADO Classic"与数据库通讯,ADO Classic 的操作方式如下:

创建并打开一个到数据库的连接。

创建并执行一条数据库命令,如:

SELECT partnumber FROM invoices WHERE price > 100

枚举得到的记录集。

关闭连接。

该方法工作得很好,但它有几个缺点。该模型需要指向数据库的有效连接是产生主要缺点的原因。如果将有许多实时连接,则服务器需要具有伸缩性且很健壮,这需要付出很高的代价。因此,要最大限度减小服务器的负载,我们需要短期连接。但是,由于连接在用户枚举记录集时处于打开状态,因此连接通常需要打开较长一段时间 - 只要用户使用数据。此外,即使保持连接处于打开状态的服务器端开销不重要,但在您希望能够使用数据的环境下,该模型也无法很好地工作(即使您只是暂时缺少网络连接)。

脱机策略

数据库连接既昂贵又必要,因此必须谨慎管理。在典型的 ADO 应用程序中,开发人员的大部分精力都花费在编写代码以确保连接的开放时间尽可能短,同时仍然能够满足应用程序用户的需要。ADO.NET 从根本上解决了 ADO 的问题:如果我们无法使连接的开销降低,至少可以使对连接的需求减少。因此,ADO.NET 从根本上讲是一个脱机策略。典型的 ADO.NET 方案操作如下:

创建一个 DataAdapter 以管理到特定数据库或其他数据源的连接。

在适配器上设置属性,以告诉适配器针对数据库要执行什么样的查询。

创建要填充的 DataSet。

在适配器上调用方法,以便为尽可能快地打开连接、执行查询、将结果保存在 DataSet 中以及关闭连接处理各种细节问题。

操作当前脱机 DataSet 中的数据。

完成数据操作后,在适配器上调用一个方法以重新打开到数据库的连接,并使用任何更改进行更新。

在我们稍后讨论适配器时,您将看到 Visual Studio Tools for Office 代替您执行了所有这些操作。

由于 DataSet 的工作方式与原始数据库十分类似,因此连接只需要在填充 DataSet 期间开放。将数据复制到 DataSet 后,您可以在任意长的时间内查询和操作 DataSet,不必担心会消耗昂贵的数据库连接。

此外,填充 DataSet 所使用的数据不一定来自连接的数据库;您还可以使用 XML 文件填充 DataSet,或者编写一个程序来添加表和行以便从头构建 DataSet。DataSet 并不了解它们所包含的数据来自何处;如果您需要该信息,所有信息都封装在适配器中。

类型化和非类型化数据集

在我们以前创建的 Word 和 Excel 项目的解决方案资源管理器中,您会找到一个包含数据库架构的 NorthwindDataSet.xsd 文件。这是一个 XML 文档,描述了组成 DataSet 的表、列和关系。解决方案资源管理器树视图中的一个子节点是 NorthwindDataSet.Designer.cs。该文件包含为 DataSet 和表适配器自动生成的代码。

第一行的声明很有趣:

public partial class NorthwindDataSet : System.Data.DataSet {

生成的类是部分类,因此,如果您需要在其中添加自己的扩展,可以在一个单独的文件中执行该操作。编辑自动生成的文件不是个好办法。更重要的是,该 DataSet 扩展了 System.Data.DataSet 类。System.Data.DataSet 由一组数据表组成。正如您所期望的那样,数据表由一组数据列和数据行组成。每个类都将各种集合作为属性公开,您可以通过 DataSet 浏览这些集合。

System.Data.DataSet 不是抽象类 - 您可以创建实例,并使用后端数据源填充它们。但那应该是非类型化 DataSet;NorthwindDataSet 是类型化 DataSet。非类型化 DataSet 为您提供很大的灵活性,但它们过于广泛,因此有些更难以使用。例如,如果要使用 Northwind 数据库文件中的数据填充非类型化 DataSet,则可以使用以下表达式访问特定数据:

name = myDataSet.Tables["Products"].Rows[1]["ProductName"];

但这种灵活性是有代价的:您可能会意外地传入错误的表名或列名,或者错误地假设某一列中存储的数据的类型。由于在编译时不知道表结构和列类型,因此编译器无法验证代码运行时不会引发异常。而且在开发代码时,智能感知® 引擎无法提供有关 DataSet 结构的任何提示。

类型化 DataSet 缓解了这些问题。类型化 DataSet 是一个扩展 DataSet 基类的类;它不但具有正规非类型化 DataSet 的所有灵活的非类型化功能,还具有按名称公开表的编译时强类型化属性。类型化 DataSet 还可以定义类型化数据表和数据行子类。

正如您在 NorthwindDataSet.Designer.cs 文件中看到的那样,类型化 DataSet 具有公共属性,使您能够编写更简单的代码,如下所示:

name = myDataSet.Products[1].ProductName;

类型化 DataSet 在许多方面扩展了非类型化 DataSet;其中最重要的几点如下:

将表作为只读属性公开,并作为类型化数据表的实例来类型化。

表的每一列都具有只读属性。

表具有返回类型化数据行的索引器。

行更改事件的事件委托可以传递类型化更改事件参数。每个行类型都具有 row-changing、row-changed、row-deleting 和 row-deleted 事件。(您可能想知道 row-adding 和 row-added 事件在哪里。changing/changed 事件传递 DataRowAction 枚举类型来指明所讨论的行是否是新创建的。)

表提供了添加和删除类型化数据行的方法。

行为每一列提供了 getter、setter 和 nullity 测试器。

简言之,使用类型化 DataSet 始终是一个好主意。弱类型化代码更加难以读取、理解和维护。

适配器

现在看一下前面讨论的 Word 或 Excel 示例中的 Startup 事件处理程序。Visual Studio 已经代替您自动生成了代码(如图 6 所示)。这里的一个新事物是 NeedsFill 方法。NeedsFill 是一个使用 Visual Studio Tools for Office 数据缓存功能的特殊 Visual Studio Tools for Office 方法。该功能允许您将某个 DataSet 标记为已缓存的,以便将该 DataSet 保存在正在自定义的文档或电子表格中。本文不对该功能进行详细介绍 - 目前,其余的代码看上去应该比较简单。如果需要从后端数据源填充两个表,则适配器会填充相应的表。

您不希望在 Startup 事件中自动填充数据表的原因有许多,这也是注释指出您可以删除自动生成的代码的原因。例如,正如前面提到的那样,您可能希望要求用户在尝试填充 DataSet 之前输入数据库密码。您可以生成新的连接字符串,然后设置适配器的 Connection.ConnectionString 属性。

或者,您可能希望让用户选择是否连接到后端。如果用户使用的连接昂贵或者速度较慢,他可能希望跳过下载大量数据的过程。无论出于何种原因,您可能不希望立刻进行连接或使用默认连接字符串,因此 Visual Studio 允许您修改该启动代码。

Visual Studio 在生成类型化 DataSet 的同时生成强类型化的自定义适配器。如果您在 NorthwindDataSet.Designers.cs 中通读了生成的适配器代码,将看到生成的适配器已经硬编码,以连接到配置文件中的连接字符串指定的数据库。大多数生成的适配器代码包含用于从后端数据存储读入类型化 DataSet 的查询代码、随后用于在DataSet 中接受所有更改的代码,以及用于更新或删除存储中的相应行的代码。

适配器负责处理打开连接、执行查询、将数据复制到 DataSet 以及关闭连接的所有细节。此时,您拥有数据的本地副本,您可以将该副本用于核心内容,而不必担心进一步加重服务器的负担。

在 DataSet 中完成数据的本地副本编辑之后,您可以通过适配器使用更改来更新数据库(通过调用适配器的 Update 方法)。随后,适配器将在后端数据库上执行各种添加、更改和删除操作。

将绑定源用作代理

Visual Studio 为什么要将控件绑定到 BindingSource 代理对象,而不是将控件直接绑定到数据表?原因是即使表中的数据当前不可用,控件也可以绑定到代理。例如,可能要根据对 Web 服务的调用派生数据,只有在初始化完成后很长一段时间,或者用户键入密码或按下某个按钮来启动数据库连接之后,才会出现这种情况。

自定义启动后,系统会创建代理对象,然后可以将控件绑定到该代理对象,即使目前没有实际数据。在获得实际数据后,绑定源会更新控件。拥有一个能够在所有数据可用之前更轻松地设置绑定的小型填充程序很有必要。

正如您在示例中看到的那样,多个控件可以共享同一个绑定源,因此具有并发性。也就是说,在更新一个控件时,链接到同一个绑定源的所有其他控件也会自动更新。不同电子表格上的控件可以共享绑定源,因此可以共享并发性。通过使用 BindingSource 对象上的 MoveNext 和 MovePrevious 方法,可以轻松地更改并发性并移到数据库中的另一条记录。

数据绑定控件

数据绑定难题的最后一部分是实际显示绑定数据的宿主控件(例如,Word 书签或 Excel 区域)或者电子表格或文档上的 Windows 窗体控件。数据绑定控件的风格有两种:简单和复杂。可以将单个数据绑定到特定属性的控件是简单数据绑定控件。可以绑定多行和/或多列的控件是复杂数据绑定控件。

在前面的示例中,Excel 中的列表对象、组合框和 DataGrid Windows 窗体控件是复杂数据绑定控件;列表对象和 DataGrid 显示一个表的多行和多列,组合框显示单列的多行。相比而言,书签和命名区域控件是简单数据绑定控件;它们只将单个数据绑定到命名区域的 Value 属性。

所有 Windows 窗体控件都是简单数据绑定控件,与几乎所有 Word 和 Excel 宿主项和宿主控件一样。(但有一个例外:Word XMLNodes 宿主控件既不是简单数据绑定控件,也不是复杂数据绑定控件。)在宿主项和宿主控件中,只有 Excel 列表对象是复杂数据绑定控件。

特别注意事项

使用数据绑定将数据按一个方向移到文档或工作簿中很简单。但是,要将数据从 Excel 或 Word 取回到数据库(假设您希望用户能够编辑数据,并将数据推回到数据库中)需要几个额外的步骤。

首先,您需要使用任何简单数据绑定宿主控件或 Windows 窗体控件上可用的 WriteValue 方法。您可以通过编写以下代码来完成此操作:

myNamedRange1.DataBindings.Item(0).WriteValue()

通常,您希望在一个更改事件中为命名区域或书签编写该代码,或者在写回数据库之前在其他某个地方编写该代码。

在本例中,该行代码可以将更改后的数据从命名区域取回到 DataSet 中。接下来,您需要在 DataSet 上调用 AcceptChanges 来告诉绑定的 DataSet 接受对其进行的更改(由于使用了 WriteValue):

MyDataSet.AcceptChanges()

此外,如果您要使用 BindingSource 对象,可以在 BindingSource 对象上调用 EndEdit。

最后,既然已将更改从数据绑定的命名区域 WriteValue 回 DataSet,并且 DataSet 已经接受更改,您就需要将修改后的 DataSet 写回到实际的数据库(通过使用填充 DataSet 的表适配器,以及在表适配器上调用 Update):

Me.MyTableAdapter.Update(Me.MyDataSet.MyTable)

请注意,如果您使用的是一个数据绑定的 Excel 列表对象,则不必执行 WriteValue 和 AcceptChanges 步骤 - 它会自动执行这两个步骤,因为它执行的是复杂数据绑定,而不是简单数据绑定。

小结

Visual Studio 2005 Tools for Office 提供了功能强大的数据绑定工具,这些工具在很大程度上和 Windows 窗体使用同一个模型。该模型允许您使用现有的数据源知识和 Visual Studio 2005 中的数据绑定来创建数据绑定的 Office 解决方案,而不必了解 Excel 和 Word 的复杂对象模型。

Eric Carter Eric Lippert 是 Microsoft 的开发人员。他们在 Visual Studio Tools for Office: Using C# with Excel, Word, Outlook, and InfoPath (Addison-Wesley Professional, 2005)Visual Studio Tools for Office: Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath (Addison-Wesley Professional, 2006) 这两本书中对 Visual Studio Tools for Office 进行了深入讨论。本文部分内容改编自 Visual Studio Tools for Office: Using C# with Excel, Word, Outlook, and InfoPath 一书,得到了 Addison-Wesley 的许可。

转到原英文页面

参与讨论(本站原创作品可提供技术支持) 涉及版权问题或文档错误请与管理员联系

相关连接:
自定义 Outlook 以便与企业应用程序集成 2007年9月28日
多图预览:微软发布Outlook Live服务 2005年6月7日

©COPYRIGHT,1999-2005,JaronSoft Corporation(佳融技术).
©Powered by SiteManager-CMS Server v6.1.05.0601 PageView:
系统开发及商务合作请点击这里与我们联系 苏ICP备05021440号