model类
继承INotifyPropertyChanged,实现双向数据同步
继承IDataErrorInfo,实现错误输出
internal class User:INotifyPropertyChanged,IDataErrorInfo
{
Dictionary<string, List<ValidationResult>> errorDic=new Dictionary<string, List<ValidationResult>>();
public string _name;
/// <summary>
/// 是否可以验证
/// </summary>
bool isValidatorName=false;
public string this[string columnName]
{
get
{
var vc = new ValidationContext(this, null, null);
vc.MemberName = columnName;
//错误缓存
var res = new List<ValidationResult>();
var result = Validator.TryValidateProperty(this.GetType().GetProperty(columnName).GetValue(this, null), vc, res);
//把所有错误存入字典
if(!errorDic.ContainsKey(columnName))
{
errorDic.Add(columnName, res);
}
else
{
errorDic[columnName] = res;
}
if(columnName=="Name"&& !isValidatorName)
{
return string .Empty;
}
if (res.Count > 0)
{
return string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray());
}
return string.Empty;
}
}
public string Error
{
get { return null; }
}
/// <summary>
/// 要验证的字段
/// </summary>
[Required(ErrorMessage = "[登录名]内容不能为空!")]
[StringLength(4, ErrorMessage = "[登录名]内容最大允许255个字符!")]
[RegularExpression("^[A-Za-z0-9]+$", ErrorMessage = "[登录名]格式不正确!")]
public string Name
{
get { return _name; }
set { _name = value;
OnPropertyChanged("Name");
isValidatorName = true;
}
}
/// <summary>
/// 双向同步处理
/// </summary>
public event PropertyChangedEventHandler? PropertyChanged;
void OnPropertyChanged( string propName)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propName));
}
/// <summary>
/// 验证所有字段是否合法
/// </summary>
/// <returns></returns>
public bool IsValidator()
{
return errorDic.Values.Sum(e=>e.Count)==0;
}
/// <summary>
/// 获取字段错误信息
/// </summary>
/// <param name="columnName"></param>
/// <returns></returns>
public List<ValidationResult> GetErrorList(string columnName)
{
if(errorDic.ContainsKey(columnName))
return errorDic[columnName];
return new List<ValidationResult>();
}
}
自定义isValidatorName字段,初始化为false,此时不输出错误
Name字段被修改时说明用户在输入了,此时isValidatorName改为true,开始验证此字段.
这样可以防止初始化页面时显示判空的错误提示.
页面
public partial class MainWindow : Window
{
User user { get; set; }
public MainWindow()
{
InitializeComponent();
user=new User();
this.DataContext = user;
}
}
页面进行数据绑定
初始化User类的实例并绑定到页面DataContext
输入框样式
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="BlueTextBox" TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Bottom" Background="Red" Foreground="White" FontSize="12" Height="14"
Width="Auto"
VerticalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" FontFamily="Arial"
Text="{Binding ElementName=ErrorBox, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
</TextBlock>
<AdornedElementPlaceholder Name="ErrorBox" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
如果有错误,显示出来
AdornedElementPlaceholder 提取了错误内容,样式中写一个TextBlock 输出错误
Text=“{Binding ElementName=ErrorBox, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}”
画页面
<Window.Resources>
<ResourceDictionary Source="TextBoxStyle.xaml"></ResourceDictionary>
</Window.Resources>
页面引用资源样式文件
<TextBox x:Name="userName" Style="{StaticResource BlueTextBox}" Width="200" Height="30">
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="true" >
</Binding>
</TextBox.Text>
</TextBox>
输入框设置样式,并绑定了页面数据的Name属性同步数据, Path=“Name”.
绑定事件输入时更新数据,UpdateSourceTrigger=“PropertyChanged”,
设置有错误时输出显示出来ValidatesOnDataErrors=“true”,
private void Button_Click(object sender, RoutedEventArgs e)
{
//验证字段是否合法
if (user.IsValidator())
{
}
}
后台验证是否通过.
总结
整体思数是model类继承IDataErrorInfo接口,当有数据修改时启用验证,并把验证错误信息返回,页面输入框的模板通过AdornedElementPlaceholder输出错误信息.