wpf验证方案讨论

      虽然wpf内部有验证方案,但在实际应用中,会出现一些问题.这里发出来与大家共同讨论.作为使用者,你喜欢哪一种呢?这里不解释数据绑定的知识,因为不够专业,怕会误导,索性不写.但我相信大家会遇到这个问题.本文是通过多个示例比较得出的想法.

1.通过继承ValidationRule抽象类,定义验证规则重写Validate方法

这里是sdk的示例代码

Code
public class AgeRangeRule : ValidationRule
    
{
        
private int _min;
        
private int _max;

        
public AgeRangeRule()
        
{
        }


        
public int Min
        
{
            
get return _min; }
            
set { _min = value; }
        }


        
public int Max
        
{
            
get return _max; }
            
set { _max = value; }
        }


        
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        
{
            
int age = 0;

            
try
            
{
                
if (((string)value).Length > 0)
                    age 
= Int32.Parse((String)value);
            }

            
catch (Exception e)
            
{
                
return new ValidationResult(false"Illegal characters or " + e.Message);
            }


            
if ((age < Min) || (age > Max))
            
{
                
return new ValidationResult(false,
                  
"Please enter an age in the range: " + Min + " - " + Max + ".");
            }

            
else
            
{
                
return new ValidationResult(truenull);
            }

        }

    }

然后是xaml的使用代码

     < TextBox  Name ="textBox1"  Width ="50"  FontSize ="15"
             Validation.ErrorTemplate
=" {StaticResource validationTemplate} "
             Style
=" {StaticResource textBoxInError} "
             Grid.Row
="1"  Grid.Column ="1"  Margin ="2" >
      
< TextBox.Text >
        
< Binding  Path ="Age"  Source =" {StaticResource ods} "
                 UpdateSourceTrigger
="PropertyChanged"   >
          
< Binding.ValidationRules >
            
< c:AgeRangeRule  Min ="21"  Max ="130" />
          
</ Binding.ValidationRules >
        
</ Binding >
      
</ TextBox.Text >
    
</ TextBox >

就是通过ValidationRules集合挂验证规则.如果逻辑不复杂的话,勉强可以接受,这里我个人认为可以作为界面的验证.但如果业务逻辑一旦发生变化,则意味着xaml文件一直需要修改,这并不是一种好的做法,并不推荐.( 而且内置的验证规则太少了,有的话还勉强用用,都需要自己重写)

2.通过正则表达式附加属性简化写法,大家应该知道,验证部分,正则表达式占了很大部分.

定义一个正则表达式类,然后通过附加属性进行验证.具体的方案,请参考这里
http://www.codeproject.com/WPF/RegexValidationInWPF.asp
然后前端xaml的使用方法
     < TextBox
      
Text =" {Binding Path=EmailAddress, UpdateSourceTrigger=PropertyChanged} "  
      jas:RegexValidator.RegexText
="^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$"  
      jas:RegexValidator.ErrorMessage
="Invalid e-mail address."  
      
/>

代码是简化了,但有个缺点,只能定义一个验证规则,也存在着我上面提到的问题,把正则写在ui上面,并不是一个好的做法,应该对其进行封装(看着这么多符号就心慌,高手可以这么做),也并不推荐的做法.

3.与业务逻辑验证绑定在一起
这种做法与上面的都不同,因为业务逻辑的判断与常规的判断比如(比如是否必填,字符匹配等),而且前端只需要绑定字段就可以了,先看前端的做法
< TextBox  Width ="100"  Grid.Column ="1"  HorizontalAlignment ="Left"  Margin ="5,5,0,5"  x:Name ="txtFirstName"  Text =" {Binding Path=FirstName, Mode=TwoWay, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True} "  ToolTip ="Enter customers first name."   />

请注意,这里并没有写什么验证规则或正则表达式哦,真正的验证在这里,验证的对象必须实现 IDataErrorInfo接口,通过索引器,可以判断对象的每个字段.
上面紧紧是FirstName,这里是通过整个对象的业务逻辑判断的,否则你需要在ui上面都定义一个验证规则,非常麻烦(比如有2个字段,你必须对两个字段都定义验证规则(即第一种方法)).这种做法是比较好的,把逻辑与ui分开了,值得推荐.sdk示例代码
  public   class  Person : IDataErrorInfo
    
{
        
private int age;

        
public int Age
        
{
            
get return age; }
            
set { age = value; }
        }


        
public string Error
        
{
            
get
            
{
                
return null;
            }

        }


        
public string this[string name]
        
{
            
get
            
{
                
string result = null;

                
if (name == "Age")
                
{
                    
if (this.age < 0 || this.age > 150)
                    
{
                        result 
= "Age must not be less than 0 or greater than 150.";
                    }

                }

                
return result;
            }

        }

    }


但还有些问题,如果我在第3点的基础上,我还要加一个普通的判断,比如必填验证,长度验证,还是逃不了验证规则这一步.
这里我们要做出选择
把规则定义在ui上(变动太大,不适合,无奈之举)
写在业务逻辑里面(这样下来,逻辑未免太复杂)

4.以元数据的形式(在属性上挂标签)

codeproject上,我找到一个比较完美的解决方案,作者自己重新定义了一套标签,使用也比较简单(代码是vb的,编译后再反编译用c#看:)),这种做法已经接近了要求.大家去看看这篇文章,非常的不错.其在还为前端提供了一个ui显示错误的一个下拉列表.不过通过这个例子,我又想到一个更好的东西.

5.使用EnterPrise Library Validation Application Block(再好不过)
由于wpf的属性使用了大量的依赖属性,我原以为这个好东西在wpf算是废了,通过第3点和第4点,我们终于可以引进这个企业级模块了。如下做法
Code
    public abstract class BaseValidationEntity<T> : IDataErrorInfo, INotifyPropertyChanged
    
{
        
IDataErrorInfo Members#region IDataErrorInfo Members

        
public string Error
        
{
            
get return null; }
        }


        
private T _entity;

        
public bool Valid()
        
{
            Validator
<T> validator = ValidationFactory.CreateValidator<T>();
            ValidationResults results 
= validator.Validate(this);
            
return results.Count == 0;
        }


        
public string this[string name]
        
{
            
get
            
{
                
                
string result = null;
                
                Validator
<T> validator = ValidationFactory.CreateValidator<T>();
                ValidationResults results 
= validator.Validate(this);
                
if (results.Count > 0)
                
{
                    
return results.First().Message;
                    
//foreach (var item in results)
                    
//{
                    
//    result += item.Message;
                    
//}
                }


                
return result;
            }

        }


        
#endregion


        
protected void OnPropertyChanged(string name)
        
{
            PropertyChangedEventHandler handler 
= PropertyChanged;
            
if (handler != null)
            
{
                handler(
thisnew PropertyChangedEventArgs(name));
            }

        }



        
INotifyPropertyChanged Members#region INotifyPropertyChanged Members

        
public event PropertyChangedEventHandler PropertyChanged;

        
#endregion

    }

然后继承之,随便定一个对象来demo
    public   class  aa:BaseValidationEntity < aa >
    
{
        
private string firstName;

        [StringLengthValidator(
410,MessageTemplate="aaa")]
        [RegexValidator(
@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", MessageTemplate = "Invalid e-mail address")]
        
public string FirstName
        
{
            
get return firstName; }
            
set { firstName = value;
            OnPropertyChanged(
"FirstName");
            }

        }

    }

我们看到熟悉的标签了,目前我认为这种方案最好,当然我们也可以通过配置xml来实现,这样真正做到了界面与逻辑分离。

上面一层的做到了逻辑上的验证,至于界面如何显示错误,我们可以通过Error属性来定制一个控件,这个暂不讨论了

在学习wpf的朋友,欢迎一起讨论。

 参考文章
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值