winform控件验证技术(转)

2011-08-18 10:10

Windows 窗体验证的主要功能

简单地说,验证是指在进行后续处理或存储之前,确保数据的完整性和准确性的过程。对于数据验证,有一条基本原则:”不要让野蛮人进门” ,即必须在表示层及早对用户输入的数据进行验证,以构成前沿验证防御。利用 UI,开发人员通常可以为最终用户构造一个更具人性化、响应性更高并提供更多信息的验证过程,同时还可以避免出现类似于跨 N 层应用程序进行不必要的双向网络通信这样的问题。

考虑图 1 所示窗体:

 

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

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

必须输入“姓名”、和“手机号码” 

 

“手机号码”必须为11位数字

 

 

实现此验证需要一个相应的基础结构,WinForm 窗体提供了该基础结构,并将其直接内置于每个控件中。为指示控件支持验证,将控件 CausesValidation 的属性设置为 True,即所有控件的默认值。 如果某个控件的CausesValidation 属性设置为 True,则当焦点切换到另一个CausesValidation 值也设置为 True 的控件时,将引发前一个控件的Validating 事件。随后,应处理Validating 以实现验证逻辑,如确保提供“姓名”。 另外,为了在验证未能通过的时候,给用户以醒目提示,需要将控件和ErrorProvider组件相结合来使用,示例代码如下

void txtName_Validating(object sender, CancelEventArgs e) {

 // 要求输入姓名

 if(txtName.Text.Trim() == "" ) {

e.Cancel = true;

errProvider.SerError(txtName,”姓名必须要输入!”)

    return;

 }  else {

          errProvider.SerError(txtName,””);

}

}

代码1 控件Validating事件处理过程

当在姓名文本框中没有输入内容时,显示的界面如图2所示。


 

图 2.  结合ErrorProvider的验证提示

窗体范围的验证

Validating 事件和ErrorProvider 组件的组合提供了一个优秀的解决方案,可以在需要时(即当用户输入数据时)动态验证每个控件。遗憾的是,对Validating 事件的依赖使该解决方案无法自动扩展为支持窗体范围的验证(当用户单击“确定” 按钮完成数据输入时,需要此验证)。单击”确定”按钮前,一个或更多个控件可能没有焦点,因此不引发其Validating 事件。窗体范围的验证通过手动调用捆绑在每个Validating 事件中的验证逻辑来实现,方法是枚举窗体中的所有控件,为每个控件设置焦点,然后调用该窗体的Validate 方法,如下所示:

void btnOK_Click(object sender, System.EventArgs e) { foreach( Control control in Controls ) {    // 在控件上设置焦点    control.Focus();    // 验证导致引发控件的验证事件,    // 如果 CausesValidation 为 True    if( !Validate() ) {
      errProvider.SetError(control,"错误提示信息");
      DialogResult = DialogResult.None;      return;    } else {
      errProvider.SetError(control , "");
    } 
   }}代码2 “确定”按钮单击,窗体范围数据验证智能数据验证框架

从工作效率的角度来看,该解决方案存在一个根本性的问题,即大型应用程序通常包含多个窗体,每个窗体通常比本文的小程序示例包含更多的控件,因此需要更多的验证代码。在 UI 日益复杂的情况下编写大量相似的代码是一项不具伸缩性的技术,因此应尽可能地避免。解决方案之一是编写一个通用的验证逻辑框架.应用该框架时,只要为窗体范围中的控件指定验证规则,则数据验证会自动在幕后进行。这有助于减少大量冗余代码,保持代码的优雅和简洁。

该验证框架总体结构如图3所示

 


                  图3 数据验证框架的总体结构



FormValidator是主类,该类用于对窗体进行自动验证,其中:

Void DoValid()方法应该在类似用户单击”确定”按钮的场景被调用,以实现窗体范围的数据验证,当应用该框架是,代码2可以简化为:

void btnOK_Click(object sender, System.EventArgs e) {

     aFormValidator.ValidateAll(); //aFormValidator代表一个FormValidator对象

 }

                  代码3 运用ValidateAll实现窗体范围的数据验证

此外,ValidateAll会指定跟踪所有的需要验证的控件,对不需要数据验证的控件不会启动验证过程

Void SetupValidatorForControl(Conbtrol controlToValidate , params IValidator[] validators)方法为每个需要数据验证的控件安装多个验证器. 当我们需要对某个控件应用多个验证规则进行数据验证的时候,再也不需要处理Validating事件,框架使用者只需要窗体的初始化时(通常是FormLoading事件)中调用SetUpValidatorForControl方法即可,示例代码如下:

void FormLoading(….) {

     SetupValidatorForControl(txtName,new RequireFieldValidator());

}

IValidator代表数据验证器,方法IsValid(controlToValidate:Control)控件进行实际的验证,如果controlToValidate控件通过该数据验证器,则返回true,否则返回false;String ErrorMessage()返回当控件没有通过该数据验证器验证时,应该显示给用户的提示信息.

AbstractValidator实现了Ivalidator接口,为ErrorMessage提供了默认实现

RequireFieldValidator,RegexFiledValidator,EmailValidator,PhoneValidator和RangeValidator都是具体的数据验证器,分别用于验证非空数据,正则表达式数据,Email数据,电话号码数据, 范围数据,是框架为调用者提供的常规数据验证器.

       如果框架提供的验证器类不能满足要求,完全可以定义自己的数据验证器类,在此给出一个验证数据必须为指定长度的示例

publicclassLengthValidator:AbstractValidator

{

        /// <summary>

        /// 最下长度

        /// </summary>

        privateint mMinLength;

        /// <summary>

        /// 最大长度

        /// </summary>

        privateint mMaxLength;

 

        /// <summary>        

        /// </summary>

        /// <param name="minLen">长度下限</param>

        /// <param name="maxLen">长度上限</param>

        /// <param name="errMsg">验证未通过时错误提示信息</param>

        public LengthValidator(int minLen, int maxLen, string errMsg)

            :base(errMsg)

        {

            if (minLen < 0)

            {

                thrownewArgumentOutOfRangeException("字段长度不能为负");

            }

            if (minLen > maxLen)

            {

                thrownewArgumentException("最大长度不能小于最下长度");

            }

            mMinLength = minLen;

            mMaxLength = maxLen;

        }

 

        /// <summary>

        /// 验证控件内容是否在指定长度范围内

        /// </summary>

        /// <param name="controlToValidate">待验证控件</param>

        /// <returns>如果在范围内,返回true;否则返回false</returns>

        publicoverridebool IsValid(Control controlToValidate)

        {

            if ((controlToValidate.Text.Length >= mMinLength) &&

                (controlToValidate.Text.Length <= mMaxLength))

            {

                returntrue;

            }

            returnfalse;

        }

    }

如果对姓名文本框(txtName)应用以下规则验证:1.姓名不能为空2.姓名必须是2-4个字符,则代码大致如下

Void FormLoading(…) {

     aFormValidate. SetupValidatorForControl(txtName,

new RequireFieldValidate(),

new LengthValidate(2,4,”姓名必须是2-4个字”));

}

该验证框架已经在笔者的多个项目中进行应用,为项目开发节省了大量事件,让开发人员完全从重复的数据验证代码中解放出来;而且,实际的使用过程也怎么该框架具有良好的扩展性,可以自己定义验证器来实现业务规则的验证;同时还具有很好的非侵入性,即框架基本不会对已有代码产生不良影响.

进一步的研究

通过AOP或者.net Attribute实现声明性的数据验证可以进一步减少程序代码量

框架源代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;

namespace StevenZhang.FormValidateFrame
{
    /// <summary>
    /// 窗体验证器,用于对窗体上的所有具有输入焦点的控件进行验证
    /// </summary>
    public class FormValidator
    {
        /// <summary>
        /// 要验证的窗体
        /// </summary>
        private Form mFormToValid;
        /// <summary>
        /// 验证错误提示控件
        /// </summary>
        private ErrorProvider mProvider;
        /// <summary>
        /// 待验证控件数组
        /// </summary>
        private List<Control> mControlsToValidate =
            new List<Control> ();
        /// <summary>
        /// 是否启动验证
        /// </summary>
        private bool mEnableValidate = true;
        /// <summary>
        /// 创建一个窗体验证器
        /// </summary>
        /// <param name="frmToValid">要验证的窗体</param>
        /// <param name="errProvider">验证所用的errProvider</param>
        public FormValidator(Form frmToValid,
            ErrorProvider errProvider)
        {
            mFormToValid = frmToValid;
            mProvider = errProvider;
        }

private bool isValid=true;

public bool IsValid

{

get

{

 retuValidAll()
rn isValid;

}

}
        /// <summary>
        /// 验证窗体的所有控件
        /// </summary>
        public void  ValidAll()
        {

           isValid=true;
            foreach (Control control in mControlsToValidate)
            {
                control.Focus();
                mFormToValid.Validate();
            }          
        }
        /// <summary>
        /// 如果为true,表示验证启动;如果为false,表示验证没有启动
        /// </summary>
        public bool EnableValidate
        {
            get
            {
                return mEnableValidate;
            }
            set
            {
                if (value == mEnableValidate)
                    return;
                else
                {
                    mEnableValidate = value;
                    foreach (Control control in mControlsToValidate)
                    {
                        control.CausesValidation = mEnableValidate;
                    }
                }
            }
        }
        /// <summary>
        /// 为窗体的所有需要验证的控件设置验证规则
        /// </summary>
        /// <param name="controlToValidate">要验证的控件</param>
        /// <param name="rules">验证规则</param>
        public void SetControlValitors(Control controlToValidate,
            params IValidator[] validators)
        {
            //判断要验证的控件是否已经存在与待验证控件数组中
           
            if(!mControlsToValidate.Contains(controlToValidate))           
                mControlsToValidate.Add(controlToValidate);

            controlToValidate.Validating += delegate(Object sender,
                CancelEventArgs e)
            {
                foreach (IValidator validator in validators)
                {
                    if (!validator.IsValid(controlToValidate))
                    {
                        e.Cancel = true;
                        mProvider.SetError(controlToValidate,
                            validator.ErrorMessage);

                    isValid=false;
                        return;
                    }
                    else
                    {
                        mProvider.SetError(controlToValidate, "");
                    }
                }
            };
               
        }      
    }
   
}



using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace StevenZhang.FormValidateFrame
{
    public interface  IValidator
    {
        /// <summary>
        /// 通过该方法对控件进行验证,如果通过验证,返回true,否则返回false
        /// </summary>
        /// <param name="controlToValid">待验证的控件</param>
        /// <returns>如果控件通过该验证,返回true;否则返回false</returns>
        bool IsValid(Control controlToValid);
        /// <summary>
        /// 验证没有通过的时候,需要显示的错误提示信息
        /// </summary>
        string ErrorMessage
        {
            get;
            set;
        }
    }
}



using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace StevenZhang.FormValidateFrame
{
    public class LengthValidator:AbstractValidator
    {
        /// <summary>
        /// 最下长度
        /// </summary>
        private int mMinLength;
        /// <summary>
        /// 最大长度
        /// </summary>
        private int mMaxLength;

        /// <summary>       
        /// </summary>
        /// <param name="minLen">长度下限</param>
        /// <param name="maxLen">长度上限</param>
        /// <param name="errMsg">验证未通过时错误提示信息</param>
        public LengthValidator(int minLen, int maxLen, string errMsg)
            :base(errMsg)
        {
            if (minLen < 0)
            {
                throw new ArgumentOutOfRangeException("字段长度不能为负");
            }
            if (minLen > maxLen)
            {
                throw new ArgumentException("最大长度不能小于最下长度");
            }
            mMinLength = minLen;
            mMaxLength = maxLen;
        }

        /// <summary>
        /// 验证控件内容是否在指定长度范围内
        /// </summary>
        /// <param name="controlToValidate">待验证控件</param>
        /// <returns>如果在范围内,返回true;否则返回false</returns>
        public override bool IsValid(Control controlToValidate)
        {
            if ((controlToValidate.Text.Length >= mMinLength) &&
                (controlToValidate.Text.Length <= mMaxLength))
            {
                return true;
            }
            return false;
        }
    }
}


using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace StevenZhang.FormValidateFrame
{
    /// <summary>
    /// 正则表达式验证器
    /// </summary>
    public class RegexValidator:AbstractValidator
    {
        /// <summary>
        /// 正则表达式对象
        /// </summary>
        private Regex mRegex;

        /// <summary>
        /// </summary>
        /// <param name="pattern">正则表达式</param>
        public RegexValidator(string pattern ,string errMsg):base(errMsg)
        {
            mRegex = new Regex(pattern);          
        }

        #region IValidator部分
        public override bool IsValid(Control controlToValidate)
        {
            return mRegex.IsMatch(controlToValidate.Text);
        }       
        #endregion
    }
}



using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace StevenZhang.FormValidateFrame
{
    /// <summary>
    /// 非空字段验证器
    /// </summary>
    public class RequiredFieldValidator:AbstractValidator
    {
        private const string DefaultErrMsg = "该内容不能为空";
        /// <summary>      
        /// </summary>       
        /// <param name="errMsg">验证不通过时的错误信息</param>
        public RequiredFieldValidator(string errMsg)
            : base(errMsg)
        {                     
        }
        public RequiredFieldValidator():base(DefaultErrMsg)
        {          
        }

        #region IValidator部分
        /// <summary>
        ///验证内容必须不为空
        /// </summary>
        /// <param name="content">要验证的内容</param>
        /// <returns></returns>
        public override bool IsValid(Control controlToValidate)
        {
            string content = controlToValidate.Text;

            if ((content == null) ||
                (content.Trim().Length == 0))
            {
                return false;
            }
            return true;
        }     
        #endregion

    }
}
abstract class AbstractValidator:IValidator
{
protected string _errorMessage;

public AbstractValidator(string errorMsg)
{
_errorMessage = errorMsg;
}
#region IValidator 成员
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMessage
{
get
{
return _errorMessage;
}
set
{
_errorMessage = value;
}
}

public abstract bool IsValid(Control controlToValidate);

#endregion
}

转载于:https://www.cnblogs.com/liubo68/archive/2012/10/23/2735177.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值