winform控件验证技术

来源:互联网 发布:学校网络舆情监控制度 编辑:程序博客网 时间:2024/04/26 15:58

winform控件验证技术

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
}
 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 跑步后脸上出盐怎么办 头发被剪的很短怎么办 孩子做事情拖拉不专注怎么办 新热水壶有味道怎么办 新买电热壶有味怎么办 两个月狗耳朵臭怎么办 狗狗牙齿变黄怎么办 人用了狗沐浴露怎么办 狗狗吞食牙膏吐怎么办? 狗狗吞食了牙膏怎么办 大猪拉稀不吃食怎么办 猪不发烧不吃食怎么办 天天吃自热米饭怎么办 喝了加热包水怎么办啊 蛋挞没有盒子装怎么办 塑料饭盒盖子被吸住了怎么办 火腿淹的有臭味怎么办 微波炉热饭盖子打不开怎么办 夏天带饭容易馊怎么办? 保温饭盒里有气打不开怎么办 保温饭盒摔了一下打不开怎么办 饭盒跟盖子盖一起打不开怎么办 玻璃杯子盖被水吸住打不开怎么办 电饭煲热剩饭没加水怎么办 微波炉碗盖子吸住了怎么办 微波炉转饭盖子吸住了怎么办 玻璃碗放进微波炉打不开怎么办 乐扣微波炉加热后打不开怎么办 美的微波炉盖子打不开怎么办 美的微波炉门都打不开了怎么办 饭煮好了有异味怎么办 一正常吃饭就胖怎么办 高铁盒饭没15的怎么办 上火车前票丢了怎么办 减肥期吃了汉堡怎么办 寿司店鳗鱼有刺怎么办 吃泡面胃难受该怎么办 吃上火的东西脸上长痘痘怎么办 减肥期间吃撑了怎么办 喝了变质的牛奶怎么办 绿豆糕吃多了会怎么办