zoukankan      html  css  js  c++  java
  • 我是如何实现一个通用的验证基类的?

    验证的基本流程和基本场景

    • 验证一个控件,其步骤如下
      • 获取控件的值
        • 提供默认的控件的取值方法
        • 可以通过注册控件的方法来注册获取某个控件的值
      • 判别要验证的类型:isNumber,NotNull……
        • 通过绑定到的实体类的特性,我们可以知道具体的类型
        • 在调用方法中指定验证的类型
      • 调用验证函数进行验证
        • 默认的调用函数
        • 通过方法传递进来的验证函数
      • 验证失败提示失败信息
        • 基本的类型有默认的提示:不能为空、必须为数字、必须为日期……
        • 通过方法传入
        • 提示的方法可以由子类进行重写,这样就能根据不同的子类方法,达到实现不同的提示类型
    • 验证多个控件,其实就是递归所有的控件组,调用“一个控件的验证”
      • 一个Form下的所有控件
      • 某个容器控件(比如PanelTabPage……)下的所有控件

    使用方法示例

    以下通过一些具体的示例来展示上述验证类的使用方法

    支持DotNetBar的控件以及使用DotNetBar的气泡控件和高亮控件进行提示

    构造函数

    private BalloonValidator(Type type)
        : base(type)
    {
        Register<TextBoxX>(new[] { "txt" }, t => ((TextBoxX)t).Text)
            .Register<ComboBoxEx>(new[] { "ddl" }, t =>
            {
                var ddl = (ComboBoxEx)t;
                if (ddl.DropDownStyle == ComboBoxStyle.DropDown)
                {
                    return ddl.Text;
                }
                return ddl.SelectedIndex > 0 ? "MSG" : string.Empty;
            })
            .Register<CheckBoxX>(new[] { "chk" }, t => ((CheckBoxX)t).CheckState == CheckState.Indeterminate ? string.Empty : "MSG")
            .Register<IntegerInput>(new[] { "ii" }, t => ((IntegerInput)t).Text);
    }
    
    public BalloonValidator(Type type, BalloonTip tip)
        : this(type)
    {
        _tip = tip;
    }
    
    public BalloonValidator(Type type, BalloonTip tip, Highlighter highlighter)
        : this(type, tip)
    {
        _highligther = highlighter;
    }
    

    重写错误验证时的提示

    public override Validator HandleError(Control ctrl, string errorMsg)
    {
        ShowBalloonTip(ctrl, errorMsg);
        if (_highligther != null) _highligther.SetHighlightColor(ctrl, eHighlightColor.Red);
    
        return this;
    }
    

    重新验证正确时的方法

    public override Validator HandleSuccess(Control ctrl)
    {
        _tip.Remove(ctrl);
        if (_highligther != null) _highligther.SetHighlightColor(ctrl, eHighlightColor.None);
        return this;
    }
    

    验证使用步骤

    在Model中设置特性

    [DataType(DataType.Currency, ErrorMessage = "“运费”必须为数字")]
    public double StartYunShu
    {
        get;
        set;
    }
    

    目前支持的特性为:

    • DataType:数据类型
      • DataType.Currency:数值类型
      • DataType.DateDataType.DateTime:日期类型
    • Required:不能为空
    • StringLengthStringLength.Max:字符长度最长不能超过多少
    • RegularExpression:符合某个正则表达式

    注意控件名称的命名规则要有一定的规范

    控件命名规则为:[控件前缀] + [Model的属性名称]

    目前系统的前缀规范为:

    • 文本框TextBox:txt
    • 下拉框ComboBox:ddl
    • 日期控件:DateTimePicker:dtp
    • 复选框:CheckBox:chk
    • 数字输入控件:IntegerInput:ii

    在CheckInput方法中进行验证

    if (!_validator.Verify(Controls)) return false;

    实际使用示例

    • 实例化一个验证类:_validator = new BalloonValidator(typeof(NTier.Entity.CWGL_AccountHis), balloonTip1, highlighter1);

    • 对所有默认的控件进行验证:if (!_validator.Verify(Controls)) return false;

    • 对控件名称和实体属性名称无法匹配的进行手动验证:if (!_validator.Verify(txtMoney, "发生金额", Validator.VerifyType.Number)) return false;——实体类NTier.Entity.CWGL_AccountHis没有类型Money这样的属性

    • 对于由多个控件组成的属性,是无法根据属性的类型进行验证的,这个时候需要手动写验证函数:if (!_validator.Verify(lblUnSureCost, "请选择费用是否确定", () => rbtnYes.Checked || rbtnNo.Checked)) return false;

    • 对于复杂的验证方法,同样可以通过自定义验证函数进行验证:

      if (!((NTier.Entity.CWGL_AccountNew)ddlFNumber1.SelectedItem).FisDetail)
      {
          if (!_validator.Verify(ddlFNumber2, "二级科目", Validator.VerifyType.Required)) return false;
          if (ddlFNumber2.SelectedIndex > 0 &&
              !((NTier.Entity.CWGL_AccountNew)ddlFNumber2.SelectedItem).FisDetail)
          {
              if (!_validator.Verify(ddlFNumber3, "三级科目", Validator.VerifyType.Required)) return false;
          }
      }
      

    实现的类的基本方法概览

    注册控件

    ///首先定义控件存储对象
    class CtrlObject
    {
        public string Key { get; private set; }
        public Type Type { get; private set; }
        public string[] Prefix { get; private set; }
        public Func<Component, object> GetValue { get; private set; }
    
        public CtrlObject(Type type, string[] prefix, Func<Component, object> getValueHandler)
        {
            if (getValueHandler == null) throw new ArgumentNullException("getValueHandler");
    
            Type = type;
            Prefix = prefix;
            GetValue = getValueHandler;
    
            Key = type.FullName;
        }
    }
    
    public Validator Register<TCtrl>(string[] prefix, Func<Component, object> getValue, bool cover = false)
    {
        var ctrlObj = new CtrlObject(typeof(TCtrl), prefix, getValue);
    
        if (!_getValueHandler.ContainsKey(ctrlObj.Key)) _getValueHandler.Add(ctrlObj.Key, ctrlObj);
        else if (cover) _getValueHandler[ctrlObj.Key] = ctrlObj;
    
        return this;
    }
    

    在构造函数中注册默认的控件

    private Validator()
    {
        Register<TextBox>(new[] { "txt" }, t => ((TextBox)t).Text)
            .Register<ComboBox>(new[] { "ddl" }, t => ((ComboBox)t).SelectedIndex > 0 ? "MSG" : string.Empty)
            .Register<DateTimePicker>(new[] { "dtp" }, t =>
            {
                var date = (DateTimePicker)t;
                if (date.Checked) return date.Value;
                return null;
            });
    }
    
    public Validator(Type t)
        : this()
    {
        if (t != null)
        {
            foreach (var p in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                if (!_properties.ContainsKey(p.Name)) _properties.Add(p.Name, p);
            }
        }
    }
    

    验证控件

    验证单一控件是否合法

    public bool Verify(Control ctrl)
    {
        var args = OnBeforeVerify(ctrl);
        return args.Canceled || ValidateInner(ctrl);
    }
    
    private bool ValidateInner(Control ctrl, bool triggerAllInvalidControl = true)
    {
        if (_properties.Count == 0) throw new Exception("请先设置要验证的对象类型!");
    
        //获取对应的处理器,如果没有,则默认不加入验证
        var handler = GetHandler(ctrl);
        if (handler == null) return true;
        var value = handler.GetValue(ctrl);
    
        var property = GetProperty(handler.Prefix, ctrl);
        if (property == null) return true;//找不到对应的属性
    
        var result = ((ValidateRequired(property, value)
                       ?? ValidateDataType(property, value))
                      ?? ValidateStingLength(property, value))
                     ?? ValidateRegularExpression(property, value);
    
        if (result != null)
        {
            if (triggerAllInvalidControl)
            {
                foreach (var key in _invalidControls.Keys)
                {
                    if (ctrl.Name.Equals(key)) continue;
                    ValidateInner(_invalidControls[key], false);
                }
            }
    
            HandleError(ctrl, result.ErrorMessage);
            if (triggerAllInvalidControl && !_invalidControls.ContainsKey(ctrl.Name))
                _invalidControls.Add(ctrl.Name, ctrl);//添加到错误列表
        }
        else
        {
            HandleSuccess(ctrl);
            if (triggerAllInvalidControl && _invalidControls.ContainsKey(ctrl.Name))
                _invalidControls.Remove(ctrl.Name);//从错误列表中删除已经验证成功的控件
        }
    
        return result == null;
    }
    

    验证某个容器下所有的控件是否合法

    /// <summary>
    /// 验证某个控件下的所有子控件
    /// </summary>
    /// <param name="ctrls">The CTRLS.</param>
    /// <returns></returns>
    public bool Verify(Control.ControlCollection ctrls)
    {
        foreach (Control ctrl in ctrls)
        {
            if (Ignore(ctrl)) continue;
    
            if (IsContainer(ctrl))
            {
                if (!Verify(ctrl.Controls)) return false;
            }
            else
            {
                if (!Verify(ctrl)) return false;
            }
        }
        return true;
    }
    

    验证是否为某个类型

    public bool Verify(Control ctrl, string name, VerifyType type)
    {
        var handler = GetHandler(ctrl);
        if (handler == null) throw new Exception(string.Format("找不到类型“{0}”的获取值的处理器!", ctrl.GetType()));
        var value = handler.GetValue(ctrl);
        if (value == null || string.IsNullOrEmpty(value.ToString()))
        {
            if (type.HasFlag(VerifyType.Required))
            {
                HandleError(ctrl, string.Format("{0}不能为空!", name));
                return false;
            }
        }
        else
        {
            if (type.HasFlag(VerifyType.Number))
            {
                if (!ConvtUtil.GetNullable<double>(value).HasValue)
                {
                    HandleError(ctrl, string.Format("{0}必须为数字!", name));
                    return false;
                }
            }
        }
    
        return true;
    }
    

    在调用验证方法时传入指定的验证函数

    public bool Verify(Control ctrl, string msg, Func<bool> verifyFunc)
    {
        var args = OnBeforeVerify(ctrl);
        if (args.Canceled) return true;
    
        if (!verifyFunc())
        {
            HandleError(ctrl, msg);
            return false;
        }
    
        HandleSuccess(ctrl);
        return true;
    }
    

    验证成功时或者失败时的处理

    public virtual Validator HandleError(Control ctrl, string errorMsg)
    {
        ctrl.Focus();
        MessageBoxHelper.ShowWarning(errorMsg);
        return this;
    }
    
    public virtual Validator HandleSuccess(Control ctrl) { return this; }
  • 相关阅读:
    Android的AndroidManifest.xml文件的详解
    Android新建项目手动添加Layout布局
    elasticsearch-搜索-评分(四)
    linux监控命令-磁盘监控
    linux监控命令-pidstat
    linux监控命令-free
    linux监控命令-vmstat
    redis-缓存设计-队列(普通队列、优先级队列、延迟队列)
    redis-缓存设计-信号量设计
    redis-缓存设计-搜索前缀匹配
  • 原文地址:https://www.cnblogs.com/marvin/p/CommonValidator.html
Copyright © 2011-2022 走看看