使用 .NET 数据绑定显示数据库中的墨迹






4.50/5 (9投票s)
本文介绍了如何将 InkPicture 控件连接到数据库。这里使用的方法适用于任何 ADO.NET 数据库或支持墨迹的控件,但本文将使用 Access 数据库和 InkPicture 控件。
引言
Visual Studio 提供了强大的数据绑定功能,允许您(开发人员)将控件连接到数据库表中的字段,并在表中当前记录更改时自动更新这些字段。其强大之处在于,您可以几乎不写代码或完全不写代码就能实现这一点。对于字符串或数字等常见数据类型,数据绑定非常简单,但当要绑定的数据是自定义类型时,会稍微复杂一些。本文将讨论这种情况,并说明如何将控件绑定到存储在数据库中的墨迹。请注意,我所说的墨迹是指 Microsoft Tablet PC SDK 中的墨迹。
本文将不讨论双向绑定(允许您通过绑定控件将数据保存到数据库),因为这将在以后的文章中介绍。由于 InkPicture 控件(来自 Tablet PC SDK)存在一些异常行为,保存墨迹的过程比读取墨迹的过程要复杂得多。
背景
本文假设您了解或有使用 Microsoft Visual Studio 中绑定控件的经验,并且能够使用 IDE 来操作连接(Connections)、数据适配器(DataAdapter)和数据集(DataSet)。
使用代码
为了使用本文中的代码,您需要在开发机上安装 Microsoft Tablet PC SDK。您可以从 Microsoft 下载 Tablet PC SDK。使用 SDK 并不需要拥有 Tablet PC。
数据库和序列化的墨迹
Tablet PC SDK 提供了一种将墨迹序列化为字节数组的方法。墨迹可以以 ISF 格式(普通或 base 64 编码)或 GIF 格式(普通或 base 64 编码)进行序列化,但无论哪种格式,最终都是一个字节数组。因此,理想的做法是使用数据库中映射到字节数组的字段。在 Microsoft Access 中,这就是“OLE 对象”类型。“Memo”类型也可以,但它映射到一个字符串,因此需要额外的转换。这种额外的转换可能会有问题,因为很难找到一种字符映射能够支持字节数组中的所有值。例如,许多字符串使用数值为零的字符来表示字符串的结尾。如果您创建的字符串包含零(当源是墨迹的字节数组时,这是很可能的),那么您将得到一个无法正确表示墨迹且无法转换回来的字符串。因此,您需要尝试使用不同的格式保存墨迹,并使用不同的字符串编码格式(有关更多信息,请查看在线帮助中的 `System.Text.Encoding`)。当您可以控制数据库时,使用二进制字段类型可以省去很多麻烦,更安全。
不言而喻,数据库中的字段不能是固定大小的(除非该大小非常大)。您无法预知给定墨迹对象将存储多少数据,因此需要一个可以根据需要增长的字段。
将墨迹绑定到控件
示例代码将 InkPicture 控件绑定到 Access 数据库中的 OLE 对象字段。通常,您会通过控件的“属性”窗口创建绑定,但由于控件的 `Ink` 属性是一种特殊类型,Visual Studio 不知道如何映射它。因此,绑定需要在代码中使用控件的 `DataBindings.Add()` 方法手动创建。第一个参数是要绑定的属性名称,第二个是您的 `DataSet` 对象名称,第三个参数是数据库中的字段名称。我倾向于使用字段名称指定表名,但您在自己的应用程序中使用什么取决于您构建 `DataSet` 的方式。
Binding binding = inkPicture1.DataBindings.Add ("Ink", myDS1, "MyTable.InkField");
绑定控件并不会神奇地让您的应用程序理解如何处理从数据库接收到的数据。请记住,数据是从数据库以字节数组的形式传入,并被分配给一个 `Ink` 类型的属性。绑定对象有一个 `Format` 事件,我们可以利用它来执行转换。
binding.Format += new ConvertEventHandler(binding_Format);
虽然 .NET 中不存在 Variant 数据类型,但该事件需要足够通用,能够支持我们传入的任何晦涩的数据类型。因此,它使用一个 `object` 变量来保存待转换的数据。事件参数告诉我们数据需要转换成什么类型,完成后,我们将该值重新赋给 `object` 变量。下面的示例代码在进行转换之前会验证传入和请求的传出数据类型。它使用 `Ink` 对象的 `Load` 方法将 `byte` 数组转换为 `Ink`。
private void binding_Format(object sender, ConvertEventArgs e)
{
Ink ink = new Ink();
if (e.DesiredType.Equals(typeof(Ink)))
{
if (e.Value.GetType().Equals(typeof(byte[])))
{
byte[] bytes = (byte[])e.Value;
if (bytes.Length>0)
{
ink.Load(bytes);
}
}
e.Value = ink;
}
}
其他注意事项
为了使本文中的代码正常工作,`InkPicture` 控件需要将其 `InkEnabled` 属性设置为 false
。这一点很重要,因为当 `InkEnabled` 属性设置为 true
时,控件的 `Ink` 属性无法在代码中修改。结果是您无法使用笔在 `InkPicture` 控件中编辑墨迹。然而,使用笔编辑墨迹并将其保存到数据库(通过绑定控件)是可能的,这将在另一篇文章中介绍。