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. 第二次项目冲刺(Beta阶段)5.21

    1.提供当天站立式会议照片一张 会议内容: ①检查前一天的任务情况,做出自我反省. ②制定新一轮的任务计划. 2.每个人的工作 (1)工作安排 队员 今日进展 明日安排 王婧 #53实现多对多查重 # ...

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

    201521123082<Java程序设计>第4周总结 标签(空格分隔): java 1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内 ...

  3. Java 第八周总结

    1. 本周学习总结 2. 书面作业 1.List中指定元素的删除 1.1 实验总结 list中可以通过list.get(i)来获取具体第几个的元素的值,再通过compareTo来对比 通过in.has ...

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

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 1.多态:使用单一接口操作多种类型的对象. 2.private修饰属性,public修饰方法 ...

  5. 201521123112《Java程序设计》第2周学习总结

    1.本周学习总结 本周在课堂面授课粗略讲了<Java学习笔记>中的第三章,其内容大部分都与上学期学习的数据结构差不多,所以只是粗略的复习了一下就带过,然后通过将PTA上的实验便于我们本周的 ...

  6. 201521123061 《Java程序设计》第一周学习总结

    1.本周学习总结 (1) Java的来历与版本演进 最早是Sun公司绿色项目Green Project 中所撰写的Strar7应用程序的程序语言: (2)Java根据应用领域分为三大平台:Java S ...

  7. 201521123081《Java程序设计》 第1周学习总结

    #1. 本周学习总结 ###JAVA是1995年SUN推出的一种简单的,跨平台的,面向对象的,分布式的,解释的,健壮的,安全的,结构的,中立的,可移植的,性能很优异的,多线程的,动态的语言.是世界上广 ...

  8. 201521123110 《Java程序设计》第1周学习总结

    第一周学习总结 本周开始了对java的初次学习接触,Java是一门新的编程语言不同于C,由于有了c的基础,对于Java的理解和学习也相对从前学C更容易些. 也学习了Java的诞生发展以及运用包括JVN ...

  9. 三分钟深入TT猫之故障转移

    结束了一周繁忙的工作,趁着周末,小编手中的键盘早已饥渴难耐了,想知道上期省略号中发生了什么有趣的故事么?且听小编娓娓道来,结尾有彩蛋. 目录 风月前场 梦回现实 模拟老鸨 会话机制 故障转移 总结 风 ...

  10. TCP/IP协议:OSI七层模型、TCP/IP四层模型的对比

    1. OSI七层和TCP/IP四层的关系 1.1 OSI引入了服务.接口.协议.分层的概念,TCP/IP借鉴了OSI的这些概念建立TCP/IP模型. 1.2 OSI先有模型,后有协议,先有标准,后进行 ...