1、ValidationRule 验证

ValidationRule:是通过ValidationRule中的的Validate方法来验证我们绑定的属性。所以我们的用法是继承ValidationRule,重写他的Validate方法。示例

public class RequiredRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value == null)
return new ValidationResult(false, "不能为空值!");
if (string.IsNullOrEmpty(value.ToString()))
return new ValidationResult(false, "不能为空字符串!"); return new ValidationResult(true, null);
}
}

而XAML中需要把错误信息显示出来。

<Window.Resources>
<ControlTemplate x:Key="ErrorTemplate">
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
</ControlTemplate>
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}">
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Text="姓名"/>
<TextBox>
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<ValidationRules:RequiredRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock Text="年龄"/>
<TextBox >
<TextBox.Text>
<Binding Path="Age" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<ValidationRules:GreaterThanRule Number="10"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>

这样显示的错误信息就会以 ToolTip和红色边框的形式显示出来。但这边如果又在TextBox里面设置ToolTip那么就会优先选择TextBox里的,也就是Style中的ToolTip遇到错误信息是不会显示出来的,而是显示TextBox中的ToolTip。所以我们可以改善一下显示的模版来解决这个问题。

<ControlTemplate x:Key="ErrorTemplate">
<DockPanel LastChildFill="true">
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
</TextBlock>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>

2、Exception 验证

Exception :我们xaml中绑定的对象是属性。所以Exception验证,就是通过属性的改变来判断是否正常。如:

 public int Age
{
get { return _age; }
set
{
if (value > 200)
{
throw new Exception("年龄不能大于200");
}
_age = value;
}
}

同样跑出的异常在Xaml中也要显示下。XAML同上。这种方式就会破坏POCO的设计原则。

3、IDataErrorInfo 验证

IDataErrorInfo:这个验证是通过我们的实体对象继承IDataErrorInfo来实现的。这里声明的this索引器来访问类的成员。

 public class BaseDataErrorInfo : IDataErrorInfo
{
private string _error; public string this[string columnName]
{
get { return GetErrorFor(columnName); }
} public string Error
{
get { return _error; }
set { _error = value; }
} public virtual string GetErrorFor(string columnName)
{
return string.Empty;
}
}
public class Person : BaseDataErrorInfo
{
public string Name { get; set; } public override string GetErrorFor(string columnName)
{
if (columnName == "Name")
if (string.IsNullOrEmpty(Name))
return "Name 不能为空"; return base.GetErrorFor(columnName);
} }

XAML同上。

4、Custom Control 验证

这里我即不想污染实体类,又想实现一个通用的Validate。我想通过我xaml绑定的属性和它所属的控件。来显示ToolTip。

  public abstract class Validator : FrameworkElement
{
static Validator()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Validator), new FrameworkPropertyMetadata(typeof(Validator)));
} public virtual string ErrorMessage { get { return string.Empty; } }
public abstract bool InitialValidation();
public FrameworkElement ElementName
{
get { return (FrameworkElement)GetValue(ElementNameProperty); }
set { SetValue(ElementNameProperty, value); }
} // Using a DependencyProperty as the backing store for ElementName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ElementNameProperty =
DependencyProperty.Register("ElementName", typeof(FrameworkElement), typeof(Validator), new PropertyMetadata(null)); public object Source
{
get { return (object)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
} // Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source", typeof(object), typeof(Validator), new UIPropertyMetadata(new PropertyChangedCallback(ValidPropertyPropertyChanged))); private static void ValidPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var validator = d as Validator;
if (validator != null)
validator.SetSourceFromProperty();
if (string.IsNullOrEmpty(e.NewValue.ToString()))
{
if (validator != null)
{
validator.IsValid = validator.InitialValidation();
if (validator.ElementName.DataContext != null)
validator.ShowToolTip();
validator.IsValid = false;
}
}
} private void ShowToolTip()
{
if (IsValid)
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1.5);
_toolTip = new ToolTip();
_toolTip.StaysOpen = true;
_toolTip.PlacementTarget = ElementName;
_toolTip.Placement = PlacementMode.Right; _toolTip.Content = ErrorMessage;
_toolTip.IsOpen = true;
timer.Tick += (sender, args) =>
{
_toolTip.IsOpen = false;
timer.Stop();
};
timer.Start();
} }
private void SetSourceFromProperty()
{
var expression = this.GetBindingExpression(SourceProperty);
if (expression != null && this.ElementName == null)
this.SetValue(Validator.ElementNameProperty, expression.DataItem as FrameworkElement); } private ToolTip _toolTip;
private DispatcherTimer timer; public bool IsValid { get; set; }
}

这是一个简单的Validate基类。提供思想。功能不完善。

然后继承这个Validator

public class RequiredValidator : Validator
{
public override string ErrorMessage { get { return "不能为空值"; } }
public override bool InitialValidation()
{
if (Source == null)
return false;
return string.IsNullOrEmpty(Source.ToString());
}
}

这里ErrorMessage是显示错误信息。

InitialValidation方法是我们要验证的规则。

代码

关于使用的小例子:

一、通过代码实现数据绑定

通过代码实现数据绑定,使用的是System.Windows.Data命名空间的Binding类,主要使用Binding类的如下的属性:

  • Source属性:绑定到的数据源
  • Mode属性:绑定的模式(OneTime、OneWay、TwoWay、OneWayToSource或Default)
  • Path属性:绑定到的数据源的属性
  • Converter属性:绑定时所使用的类型转换器

在绑定目标控件上使用SetBinding方法添加数据绑定。例如将MyData的Name属性绑定到txtName控件的Text属性上,使用MyColorConverter转换器将MyBindingColor的ColorObject属性绑定到rec控件的Fill属性上:

   1: MyData data = new MyData();
   2:  
   3: Binding binding1 = new Binding();
   4: binding1.Source = data;
   5: binding1.Mode = BindingMode.OneWay;
   6: binding1.Path = new PropertyPath("Name");
   7:  
   8: txtName.SetBinding(TextBox.TextProperty, binding1);
   9:  
  10:  
  11: MyBindingColor color = new MyBindingColor();
  12:  
  13: Binding binding2 = new Binding();
  14: binding2.Source = color;
  15: binding2.Mode = BindingMode.OneWay;
  16: binding2.Path = new PropertyPath("ColorObject");
  17: binding2.Converter = new MyColorConverter();
  18:  
  19: rec.SetBinding(Rectangle.FillProperty, binding2);

二、实现绑定数据的验证:

对于绑定数据的验证,系统采用如下的机制:

使用 WPF 数据绑定模型可以将 ValidationRules 与 Binding 对象相关联。当绑定目标的属性向绑定源属性传递属性值时(仅限TwoWay模式或OneWayToSource模式),执行ValidationRule中的Validate方法,实现对界面输入数据的验证。

定义验证可以采用以下三种:

  • DataErrorValidationRule:检查由源对象的 IDataErrorInfo 实现所引发的错误,要求数据源对象实现System.ComponentModel命名空间的IDataErrorInfo接口。

例如,定义一个学生信息类,要求其学生成绩在0到100间,学生姓名的长度在2到10个字符间:

   1: public class StudentInfoWithValidation : IDataErrorInfo
   2: {
   3:     #region 构造方法
   4:     public StudentInfoWithValidation()
   5:     {
   6:         StudentName = "Tom";
   7:         Score = 90;
   8:     }
   9:     public StudentInfoWithValidation(string m_StudentName,double m_Score)
  10:     {
  11:         StudentName = m_StudentName;
  12:         Score = m_Score;
  13:     }
  14:     #endregion
  15:  
  16:     #region 属性
  17:     public string StudentName
  18:     {
  19:         get; set;
  20:     }
  21:     public double Score
  22:     {
  23:         get; set;
  24:     }
  25:     #endregion
  26:  
  27:     #region 实现IDataErrorInfo接口的成员
  28:     public string Error
  29:     {
  30:         get 
  31:         {
  32:             return null;
  33:         }
  34:     }
  35:  
  36:     public string this[string columnName]
  37:     {
  38:         get
  39:         {
  40:             string result = null;
  41:  
  42:             switch (columnName)
  43:             {
  44:                 case "StudentName":
  45:                     // 设置StudentName属性的验证规则
  46:                     int len = StudentName.Length;
  47:                     if (len < 2 || len > 10)
  48:                     {
  49:                         result = "StudentName length must between 2 and 10";
  50:                     }
  51:                     break;
  52:                 case "Score":
  53:                     // 设置Score属性的验证规则
  54:                     if (Score < 0 || Score > 100)
  55:                     {
  56:                         result = "Score must between 0 and 100";
  57:                     }
  58:                     break;
  59:             }
  60:  
  61:             return result;
  62:         }
  63:     }
  64:     #endregion
  65: }

在界面上,定义两个TextBox绑定到StudentName和Score两个属性上,并设置其采用DataErrorValidationRule:

   1: <Window x:Class="WPFDataBindingDemo.WinDataErrorValidationRuleDemo"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:local="clr-namespace:WPFDataBindingDemo"
   5:     Title="WinDataErrorValidationRuleDemo" Height="154" Width="300">
   6:     <Canvas Height="116" x:Name="mainCanvas">
   7:         <Canvas.Resources>
   8:             <local:StudentInfoWithValidation x:Key="myData" />
   9:         </Canvas.Resources>
  10:         <Canvas.DataContext>
  11:             <Binding Source="{StaticResource myData}" />
  12:         </Canvas.DataContext>
  13:         <Label Canvas.Left="10" Canvas.Top="10" Height="28" Name="label1" Width="120">StudentName:</Label>
  14:         <Label Canvas.Left="10" Canvas.Top="36" Height="28" Name="label2" Width="120">Score:</Label>
  15:         <TextBox Canvas.Left="136" Canvas.Top="12" Height="23" Name="textBox1" Width="120">
  16:             <TextBox.Text>
  17:                 <Binding Path="StudentName" 
  18:                          Mode="TwoWay" 
  19:                          UpdateSourceTrigger="PropertyChanged"
  20:                          ValidatesOnDataErrors="True" />
  21:             </TextBox.Text>
  22:         </TextBox>
  23:         <TextBox Canvas.Left="136" Canvas.Top="41" Height="23" Name="textBox2" Width="120">
  24:             <TextBox.Text>
  25:                 <Binding Path="Score" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
  26:                     <!--与上一个TextBox控件的写法作用相同-->
  27:                     <Binding.ValidationRules>
  28:                         <DataErrorValidationRule />
  29:                     </Binding.ValidationRules>
  30:                 </Binding>
  31:             </TextBox.Text>
  32:         </TextBox>
  33:         <Button Canvas.Left="12" Canvas.Top="79" Height="23" Name="button1" Width="118" Click="button1_Click">Get Student Info</Button>
  34:         <Button Canvas.Left="136" Canvas.Top="79" Height="23" Name="button2" Width="118" Click="button2_Click">Get Validate State</Button>
  35:     </Canvas>
  36: </Window>

 

 

从执行的结果上来看,当验证出现错误(即索引器属性返回的字符串不为空时),系统默认给出一种验证错误的显示方式(控件以红色边框包围),但是需注意两点:

    • 产生验证错误,验证后的数据仍然会更改数据源的值
    • 如果系统出现异常,如成绩值输入 “90d”,则系统不会显示错误,控件上的输入值也不赋值到数据源。这种情况下,需要使用ExceptionValidationRule。
  • ExceptionValidationRule:即当绑定目标的属性值向绑定源的属性值赋值时引发异常所产生的验证。此种方式若实现自定义的逻辑验证,通常设置数据源的属性的Set访问器,在Set访问器中,根据输入的值结合逻辑,使用throw抛出相应的异常。

例如上例中,对于Score对应的TextBox,再加入ExceptionValidationRule:

   1: <TextBox Canvas.Left="136" Canvas.Top="41" Height="23" Name="textBox2" Width="120">
   2:     <TextBox.Text>
   3:         <Binding Path="Score" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
   4:             <!--与上一个TextBox控件的写法作用相同-->
   5:             <Binding.ValidationRules>
   6:                 <DataErrorValidationRule />
   7:                 <ExceptionValidationRule />
   8:             </Binding.ValidationRules>
   9:         </Binding>
  10:     </TextBox.Text>
  11: </TextBox>

  • 自定义验证规则:定义一个类,继承ValidationRule抽象类,实现其Validate方法,验证某一输入。

例如,定义一个类,用来验证输入的Email地址是否合法(验证的Email允许为字符串的空值String.Empty,但有输入必须符合Email的格式要求)

在学生类中添加Email可读可写属性(并不做相应的验证,忽略其他重复代码):

   1: public string Email
   2: {
   3:     set; get;
   4: }

定义一个类,实现Email格式验证:

   1: using System.Globalization;
   2: using System.Text.RegularExpressions;
   3: using System.Windows.Controls;
   4:  
   5: namespace WPFDataBindingDemo
   6: {
   7:     public class EmailValidationRule : ValidationRule
   8:     {
   9:         public override ValidationResult Validate(object value, CultureInfo cultureInfo)
  10:         {
  11:             bool isValid = false;
  12:             string message = null;
  13:  
  14:             // 检查输入值不为空,且是字符串
  15:             if (value != null && value is string)
  16:             {
  17:                 string email = value.ToString();
  18:  
  19:                 // 检查输入的字符串是否为String.Empty
  20:                 if (email != string.Empty)
  21:                 {
  22:                     string emailFormartRegex =
  23:                         @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|" +
  24:                         @"(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
  25:                     
  26:                     // 检查输入的字符串是否符合Email格式
  27:                     isValid = Regex.IsMatch(email, emailFormartRegex);
  28:  
  29:                     if (! isValid)
  30:                     {
  31:                         message = "Input string not match Email Format";
  32:                     }
  33:                 }
  34:                 else
  35:                 {
  36:                     // 输入的字符串为字符串空值时,认为验证通过
  37:                     isValid = true;
  38:                 }
  39:             }
  40:             else
  41:             {
  42:                 message = "Input value is NULL or is not string.";
  43:             }
  44:  
  45:             // 返回验证结果(ValidationResult对象)
  46:             return new ValidationResult(isValid,message);
  47:         }
  48:     }
  49: }

在界面上:

   1: <TextBox Canvas.Left="104" Canvas.Top="70" Height="23" Name="textBox3" Width="152">
   2:     <Binding Mode="TwoWay" Path="Email" UpdateSourceTrigger="PropertyChanged">
   3:         <Binding.ValidationRules>
   4:             <local:EmailValidationRule />
   5:         </Binding.ValidationRules>
   6:     </Binding>
   7: </TextBox>

三、为数据验证提供视觉效果

在数据验证错误后,可以通过以下两种方式提供相应的视觉效果:

  • 定义Style及相应的触发器

如果要使输入的控件的外观发生变化,可以使用Style。例如上例中出错,使输入的文本框的背景颜色和字体颜色发生变化,并提供ToolTip显示错误信息,可以定义如下的Style:

   1: <Style TargetType="TextBox">
   2:     <Setter Property="Background" Value="White" />
   3:     <Setter Property="Foreground" Value="Black" />
   4:     <Style.Triggers>
   5:         <Trigger Property="Validation.HasError" Value="True">
   6:             <Setter Property="Background" Value="#DDD" />
   7:             <Setter Property="Foreground" Value="Red" />
   8:             <Setter Property="ToolTip"
   9:                     Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}"/>
  10:         </Trigger>
  11:     </Style.Triggers>
  12: </Style>

效果如下:

  • 定义控件模板

如果要为相应的控件添加一些辅助的控件,可以使用控件模板,如出现验证错误时,不使用系统默认的红色边框,而是在文本框后添加一个红色的星号:

   1: <ControlTemplate x:Key="validErrorTextBoxTemplate">
   2:     <DockPanel>
   3:         <AdornedElementPlaceholder/>
   4:         <TextBlock Foreground="Red" FontSize="20">*</TextBlock>
   5:     </DockPanel>
   6: </ControlTemplate>

并在每一个输入的TextBox中添加:

   1: Validation.ErrorTemplate="{StaticResource validErrorTextBoxTemplate}"

转载:http://www.cnblogs.com/fuchongjundream/p/3844051.html

关于WPF的验证的更多相关文章

  1. wpf数据验证实例及常用方法小结

    虽然标题是wpf数据验证,但并不是对IDataErrorInfo.ValidationRule.属性中throw Exception这几种验证方式的介绍: 之前做项目时(例如员工工资管理),根据员工编 ...

  2. WPF数据验证

    当填写表单时,需要对填写的内容进行验证,检查数据是否符合要求,比如字符串的长度.日期的格式.数字等.WPF支持自定义验证规则,并提供可视化反馈,以便在输入无效值时向用户发出通知. 下面的示例将演示一个 ...

  3. WPF MVVM 验证

    WPF MVVM(Caliburn.Micro) 数据验证 书接前文 前文中仅是WPF验证中的一种,我们暂且称之为View端的验证(因为其验证规是写在Xaml文件中的). 还有一种我们称之为Model ...

  4. WPF 自动验证

    WPF中TextBox的自动验证: 演示 : 用以下两个TextBox分别显示验证IP和非空值验证,先看效果: IP自动验证效果: 非空值自动验证效果: 第一步:定义TextBox验证的样式: < ...

  5. WPF数据验证方式

    WPF有两种数据验证的方式: 1 在数据对象上进行验证:普通属性验证或者实现IDataErrorInfo接口 2 可以再绑定规则上进行验证:ExceptionValidationRule异常验证规则 ...

  6. WPF TextBox 验证输入

    //验证输入为数字private void txt_time_KeyDown(object sender, KeyEventArgs e){ if (!((e.Key >= Key.D0 &am ...

  7. WPF mvvm 验证,耗时两天的解决方案

    常用类 类名 介绍 ValidationRule 所有自定义验证规则的基类.提供了让用户定义验证规则的入口. ExceptionValidation 表示一个规则,该规则检查在绑定源属性更新过程中引发 ...

  8. WPF 绑定 验证

    <TextBox Grid.Column="1" Margin="1" Text="{Binding Name, ValidatesOnExce ...

  9. WPF数据验证(4)——响应与获取验证错误

    1780 前面的示例中,有关用户接受到错误的唯一指示是在违反规则的文本框周围的红色轮廓.为了提供更多信息,可以处理 Error 事件,但存储或清除错误时会引发该事件,但前提是必须确保已将 Bindin ...

随机推荐

  1. 如何使用Git和码云Git@OSC

    1.Git简介 关于Git是什么,阅读博客Git简介 2.Git 基础 Git命令很多,常用命令如下图 Workspace:工作区 Index/Stage :暂存区 Local Repository: ...

  2. 201521123082 《Java程序设计》第8周学习总结

    201521123082 <Java程序设计>第8周学习总结 标签(空格分隔):Java 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 ...

  3. 201521123008《Java程序设计》第四周学习总结

    1.本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 1.包的命名规范 2.面向对象设计:名词/动词 3.类的设计技巧:一定将属性设计为私有priv ...

  4. 201521123056《Java程序设计》 第2周学习总结

    1. 本周学习总结 String类: 不可变字符串型: 粗略介绍了枚举类型: 完全限定类名: 泛型数组列表的应用: 2. 书面作业 Q1.使用Eclipse关联jdk源代码,并查看String对象的源 ...

  5. 201521123035《Java程序设计》第十二周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...

  6. 201521123052 《Java程序设计》 第13周学习总结

    1. 本周学习总结 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 返回的IP地 ...

  7. 201521123045 《Java程序设计》第12周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...

  8. Java课程设计 购物车系统(个人博客)

    1. 团队课程设计博客链接 课程设计 2. 个人负责模块或任务说明 编写ShoppingCart类,连接数据库 编写updateCart类,从数据库中获取商品信息,获取指定编号的商品信息 编写User ...

  9. 201521123024 《Java程序设计》 第九周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  10. Day-14: 常用的内建模块

    collections包含对tuple.list.dict等派生出新功能 namedtuple用来为tuple类型派生出一个新名字的tuple类,并提供用属性引出的功能. >>> f ...