技术开发 频道

Windows Forms中通过自定义组件实现统一的数据验证


窗体级验证

    Validating和ErrorProvider这对组合是一个不错的解决方案,可以在用户输入数据的时候进行验证。不幸的是,这种方法可能会使得我们无法进行窗体级的验证,而这在用户点击OK按钮提交数据时显然是必要的,因为用户在点击OK按钮前,有些控件可能未曾获得过焦点,它们的控件级验证代码也就不起作用了。先看看窗体级验证的代码:
foreach (Control ctrl in this.Controls) { ctrl.Focus(); if (!Validate()) { this.DialogResult = DialogResult.None; return; } }
    但Cancel按钮就不需要实现窗体级的验证了,它的工作往往是简单地将窗体关闭。但是现在,如果当前拥有焦点的控件数据是无效的,Cancel按钮将不能点击,因为Cancel按钮的CausesValidation属性默认为true,焦点会一直停留在无效的控件上。我们只要将Cancel按钮的CausesValidation属性设置为false就好了。
    注意:这里的窗体应当是模式窗体,否则即使CausesValidation属性设置为false,也不能点击。

    至此,使用数十行代码,我们的AddEmployee窗体就可以支持基本的验证了。

编程式验证 vs. 声明式验证

    从生产力的角度来看,上面的解决方案有一个根本的问题:如果一个程序包含多个窗体,而每个窗体又包含多个控件,那么将需要大量的用于验证的代码。这些代码增大了UI的复杂性,使得程序难以维护,显式是应当避免的。一种方法是将那些通用的验证逻辑抽象为可重用的类型。有了这样的类型,还仅仅是第一步,它仍需要编写代码。{TODO}我们需要这样的解决方案:它具有Windows Forms UI的特点,因此Windows Forms组件或控件是我们不错的选择。以这种方式封装后,开发人员的工作就变成从工具箱上拖一个组件或控件放到窗体上,通过诸如属性浏览器(Property Browser)这样的设计期特性来配置它,然后让Windows Forms设计器帮我们将这些配置转换为代码,这些代码会出现在InitializeComponent方法中。这样原来的编程式(programmatic)体验变成了声明式(declarative)体验,而后者往往意味着高效。

添加设计期支持

    第一步是添加设计期的支持,如果我们的实现不需要UI支持,可以从三种设计期组件继承:System.ComponentModel.Component, System.Windows.Forms.Control和 System.Windows.Forms.UserControl. Component,否则可以继承Control或UserControl。Control和UserControl的不同之处在于其呈现的方式,前者需要编写代码来呈现它,而后者则通过其它控件或组件来呈现它。我们在前面使用的验证代码没有绘制任何内容,而是借助于ErrorProvider来提示用户。因此,Component是我们最合适的选择。

Imitation Is the Sincerest Form of Flattery

    下一步是要确定我们需要哪些种类的验证组件,可以参考一下ASP.NET中验证控件的实现机制。这样能保持一定的一致性,而且也不需要”重新发明轮子”了。这样那些ASP.NET的开发人员也更容易上手。ASP.NET现在提供了如下的验证控件:

验证控件 描述 RequiredFieldValidator 计算输入控件的值以确保用户输入值。 RegularExpressionValidator 计算输入控件的值,以确定该值是否与某个正则表达式所定义的模式相匹配。 CompareValidator 将由用户输入到输入控件的值与输入到其他输入控件的值或常数值进行比较。 RangeValidator 检查输入控件的值是否在指定的值范围内。 CustomValidator 对输入控件执行用户定义的验证。
    同时我们还要考虑可扩展性,开发人员在必要的时候可以较为容易地开发自定义的验证组件。最后,这个实现应当利用Windows Forms中已有的验证机制(前面提及的部分)。
0
相关文章