ValidationRules
ExceptionValidationRule
XAML代码:
<TextBox Name="tb2">
<TextBox.Text>
<Binding Path="Value" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!--捕获到框架自带的异常-->
<TextBlock Text="{Binding ElementName=tb2,Path=(Validation.Errors)[0].ErrorContent}" Foreground="Red"/>
显示结果:
注意:如果写ExceptionValidationRule的时候,报错是英文的,如果没有写,报错是中文的,都会有报错捕捉。都会有验证错误,因为咱这里的值是int类型,系统也会捕捉到,所以看个人所需
使用事件进行捕捉:
方法:Validation.GetHasError() 是否有报错
Validation.GetErrors() 获得报错信息
属性:ErrorContent 报错信息
private void Button_Click(object sender, RoutedEventArgs e)
{
// 是否有报错
if (Validation.GetHasError(this.tb1))
{
// 获取报错
var errors = Validation.GetErrors(this.tb1);
var errStr = errors[0].ErrorContent;
}
// 是否有报错
if (Validation.GetHasError(this.tb2))
{
// 获取报错
var errors = Validation.GetErrors(this.tb2);
var errStr = errors[0].ErrorContent;
}
}
自定义ValidationRule
继承ValidationRule,并重写方法 Validate
C#代码:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace XH.BindingLesson.DataValidation
{
// 实际的调用实际 是在界面上的控件被绑定的属性发生变化的时候
// 继承 ValidationRule
public class ValueValidation : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
// 做值的校验规则
// value参数指的是目标值
if(int.TryParse(value.ToString(), out int v))
{
if (v == 123)
return new ValidationResult(false, "值不可以为123");
}
else
return new ValidationResult(false, "输入信息不是数值");
return new ValidationResult(true,null);
}
}
}
XAML使用:
<TextBox Name="tb3">
<TextBox.Text>
<Binding Path="Value" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:ValueValidation />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock Text="{Binding ElementName=tb3,Path=(Validation.Errors)[0].ErrorContent}" Foreground="Red"/>
效果显示:
IDataErrorInfo
需要继承IDataErrorInfo接口,然后完成两个方法
public class DataBase : IDataErrorInfo
{
public string Error { get; set; }
// 索引 获取某一列的值
public string this[string columnName] => throw new NotImplementedException();
}
在外面可以根据类名[列名]调用第二个方法:类似string[0]
每次,属性值更新时候,会调用这个方法:
xaml代码:
ValidatesOnDataErrors 打开类中的IDataErrorInfo的属性验证,如果不开,不用调用以上方法
<TextBox Name="tb4"
Text="{Binding Value,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" />
<TextBox Name="tb5"
Text="{Binding MyProperty,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" />
<TextBox Name="tb6"
Text="{Binding MyProperty1,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" />
<TextBlock Text="{Binding ElementName=tb4,Path=(Validation.Errors)[0].ErrorContent}"
Foreground="Red"/>
<TextBlock Text="{Binding ElementName=tb5,Path=(Validation.Errors)[0].ErrorContent}"
Foreground="Red"/>
<TextBlock Text="{Binding ElementName=tb6,Path=(Validation.Errors)[0].ErrorContent}"
Foreground="Red"/>
写法一:
可以根据每一列的值,进行单独判断
public string this[string columnName]
{
get
{
if (columnName == "Value" && this.Value >1000)
{
return "Value 值大于 1000!!!【IDataErrorInfo】";
}
if (columnName == "MyProperty" && this.MyProperty.Length > 50)
{
return "MyProperty 长度大于 50!!!【IDataErrorInfo】";
}
return "";
}
}
写法二:
利用反射,根据特性来判断:
在字段上方写特性 可以根据特性反射判断
[MaxLength(100)]
[Url] // 判断url是否合法
[EmailAddress(ErrorMessage = "邮箱地址不正确")] // 邮箱地址
[CheckRepeat(ErrorMessage = "输入信息有误")]
[IPCheck(ErrorMessage ="IP不对")]
public string MyProperty1 { get; set; } = "";
public string this[string columnName]
{
get
{
// 使用反射
PropertyInfo pi = this.GetType().GetProperty(columnName);
// 检查当前属性是否添加了指定的特性
// IsDefined 判断是否有特性
if (pi.IsDefined(typeof(MaxLengthAttribute)))
{
// 获取当前属性上指定的特定示例 一般是需要获取特性示例中某些值的时候使用
MaxLengthAttribute ma = (MaxLengthAttribute)pi.GetCustomAttribute(typeof(MaxLengthAttribute));
string value = pi.GetValue(this).ToString();
if (value.Length > ma.Length)
{
//return $"{pi.Name} 长度大于 {ma.Length}!!!【IDataErrorInfo】";
return ma.ErrorMessage;
}
}
return "";
}
}
正则表达式
自定义特性:
需要继承:ValidationAttribute 或者Attribute
建议继承ValidationAttribute 可以直接重写验证方法
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace XH.BindingLesson
{
public class IPCheckAttribute : ValidationAttribute
{
public override bool IsValid(object? value)
{
// 检查IP格式
// 正则表达式
// 核心:字符串中每个字符逐个判断
// 192.168.1.2
// 使用.间隔
// 每个间隔的数字都是0-255
// \. \d
string patternIpv4 = @"\b(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4])\b";
return Regex.IsMatch(value.ToString(), patternIpv4);
//return base.IsValid(value);
}
}
}
在需要验证的类中,字段中,写入以下:
[IPCheck(ErrorMessage ="IP不对")]
public string MyProperty1 { get; set; } = "";
public string this[string columnName]
{
get
{
// 自定义检验IP
if (pi.IsDefined(typeof(IPCheckAttribute)))
{
IPCheckAttribute ia = pi.GetCustomAttribute<IPCheckAttribute>();
if (!ia.IsValid(pi.GetValue(this)))
{
return ia.ErrorMessage;
}
}
return "";
}
}
显示结果如下:
扩展:把报错写在TextBox模板中
xaml代码:模板代码:
<Window.Resources>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="3" />
<Setter Property="Height" Value="35" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5">
<Grid>
<ScrollViewer Name="PART_ContentHost" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/>
<!--主要是这个,可以显示报错信息-->
<TextBlock Text="{Binding Path=(Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource Mode=TemplatedParent}}"
HorizontalAlignment="Right"
Name="error"
Visibility="Collapsed"
Foreground="Red"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--哪个控件使用,就是哪个控件的报错信息-->
<Trigger Property="Validation.HasError" Value="True">
<Setter TargetName="error" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
注意:
1、TextBlock报错的显示绑定方式,
2、触发器的属性 Validation.HasError
显示结果如下: