日期:2008-04-22  浏览次数:20608 次

摘要:数据验证是确保正常的数据捕获以及后续处理和报告的关键步骤。本文介绍了 Windows 窗体固有的程序验证基础结构,并以此为基础开发了用于提供更高效验证功能的自定义验证组件库,该验证功能与使用 ASP.NET 的验证控件相似。


下载 winforms03162004_sample.msi 示例文件。


本页内容
引言
Windows 窗体验证的主要功能
程序验证与声明性验证
建立设计时支持
模仿是最真诚的恭维
必需字段验证程序简介
BaseValidator:分治法
一个放便士,一个放英镑
已完成的自定义验证基础结构
结论
其他自定义验证解决方案
C# 与 Visual Basic .NET
Genghis
致谢
参考资料

引言
大家都把我称作怪人,我最喜欢的影片之一是 Amazon Women on the Moon,该片模仿了二十世纪五十年代的 B 级科幻电影,风格同 The Kentucky Fried Movie 一样,由几个喜剧短片组成。其中的一个短片“两份身份证明”,讲述了 Karen 和 Jerry(分别由 Rosanna Arquette 和 Steve Guttenberg 扮演)在他们初次相会的晚上发生的故事。故事从 Jerry 到达 Karen 的公寓开始。经过几分钟轻松友好的谈话后,Karen 突然要求 Jerry 出示两份身份证明-一张信用卡,一份有效的驾驶执照。Karen 通过身份证明对 Jerry 进行约会检查,正是这种突然的变化构成了该喜剧的主线。遗憾的是,Jerry 没有通过身份检查,Karen 因此拒绝了此次约会。除了滑稽可笑以外,这个故事还具有现实意义,Windows 窗体开发人员从中可以清楚地认识到:应始终对数据进行验证,以免出现意外情况,就像对剧中的 Steve Guttenberg 进行约会检查一样。相反,成功的数据验证就像对剧中的 Rosanna Arquette 进行约会检查一样,这对于该短剧的作者来说会是一件相当愉快的事情。


Windows 窗体验证的主要功能
简单地说,验证是指在进行后续处理或存储之前,确保数据的完整性和准确性的过程。尽管验证在数据层和业务规则应用程序层中都可以实现,但应将其包含在表示层中,以构成前沿验证防御。利用 UI,开发人员通常可以为最终用户构造一个更具人性化、响应性更高并提供更多信息的验证过程,同时还可以避免出现类似于跨 N 层应用程序进行不必要的双向网络通信这样的问题。验证可以包含类型、范围和业务规则检查,图 1 中的窗体可以应用所有这些类型的验证。



图 1. 要求验证的 Add New Employee 窗体

该窗体需要验证以下内容:

• 必须输入“姓名”、“出生日期”和“电话号码”

• “出生日期”必须是有效的日期/时间值

• “电话号码”必须符合澳大利亚电话号码格式:(xx) xxxx xxxx

• 新员工的年龄至少为 18 周岁


实现此验证需要一个相应的基础结构,Windows 窗体提供了该基础结构,并将其直接内置于每个控件中。为指示控件支持验证,将控件 CausesValidation 的属性设置为 True,即所有控件的默认值。 如果某个控件的 CausesValidation 属性设置为 True,则当焦点切换到另一个 CausesValidation 值也设置为 True 的控件时,将引发前一个控件的 Validating 事件。随后,应处理 Validating 以实现验证逻辑,如确保提供“姓名”。

void txtName_Validating(object sender, CancelEventArgs e) {
// 要求输入姓名
if(txtName.Text.Trim() == "" ) {
e.Cancel = true;
return;
}
}

Validating 提供了一个 CancelEventArgs 参数,通过设置该参数的 Cancel 属性可以指示该字段是否有效。如果 Cancel 为 True(无效字段),则焦点将停留在无效控件上。如果设置为默认值 False(有效字段),则将引发 Validated 事件,同时焦点将切换到新控件。图 2 演示了此过程。



图 2. Windows 窗体验证过程

您所要做的是以可视方式通知用户其输入数据的有效性,直觉告诉我们使用状态栏实现此功能比较合适。从可视化角度而言,该技术存在两个问题:

1.
状态栏只能显示一个错误,而一个窗体可能包含多个无效控件。

2.
由于状态栏通常位于窗体底部,因此很难确定错误消息究竟针对哪个控件。


经证实,在针对一个或更多控件提供错误通知方面,ErrorProvider 组件是一个更出色的机制。该组件组合使用了图标和工具提示向用户发出错误通知,并在相关控件的旁边显示相应的消息,如图 3 所示。



图 3. ErrorProvider 演示

启用该组件很简单,只需将 ErrorProvider 组件拖到一个窗体并配置其图标、闪烁速率和闪烁样式,然后即可将 ErrorProvider 合并到验证代码:

void txtName_Validating(object sender, CancelEventArgs e) {
// 需要输入姓名
if(txtName.Text.Trim() == "" ) {
errorProvider.SetError(txtName "Name is required");
e.Cancel = true;
return;
}
// 姓名有效
errorProvider.SetError(txtName, "");
}

CausesValidation、Validating 和 ErrorProvider 提供了实现按控件验证的基础结构,可将其实现方式重复用于其他控件,如 txtDateOfBirth 和 txtPhoneNumber:

void txtDateOfBirth_Validating(object sender, CancelEventArgs e) {
DateTime dob;
// 需要输入 DOB,且 DOB 必须是有效日期
if( !DateTime.TryParse(txtDateOfBirth.Text, out dob) ) {
errorProvider.SetError(txtDateOfBirth, "Must be a date/time value");
e.Cancel = true;
return;
}
// 年龄至少为十八周岁
if( dob > DateTime.Now.AddYears(-18) ) {
errorProvider.SetError(txtDateOfBirth, "Must be 18 or older");
e.Cancel = true;
return;
}
// DOB 有效
errorProvider.SetError(txtDateOfBirth, "");
}
void txtPhoneNumber_Validating(object sender, CancelEventArgs e) {
// 需要输入电话号码,且格式必须符合澳大利亚电话号码格式