WPF中使用IDataErrorInfo进行规则验证
WPF中使用IDataErrorInfo进行数据对象验证
使用 IDataErrorInfo 进行数据对象验证主要有以下步骤:
1、定义一个集合,用于收集错误信息:
private Dictionary<string, string> dataErrors = new Dictionary<string, string>();
2、需要验证的对象的类需要实现 IDataErrorInfo 接口:
- 具体的数据验证在 this[string columnName] 的 get 访问器中进行。为了防止在处理验证信息时进行大量的条件判断,在这里使用了命名空间 System.ComponentModel.DataAnnotations,将验证条件分离,以 Attribute 的形式关联到每个字段上。
- 错误信息在这里存储在集合 dataErrors 中,所以需要补充两个方法,用于操作错误dataErrors 。
- 实现以上处理的 ViewModel 代码如下:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
namespace IDataErrorInfoDemo.ViewModel
{
[MetadataType(typeof(MainViewModel))]
public class MainViewModel : ViewModelBase, IDataErrorInfo
{
public MainViewModel()
{
SaveCommand = new RelayCommand(() =>
{
if (dataErrors.Count == 0) MessageBox.Show("验证通过!");
else
{
StringBuilder sb = new StringBuilder();
sb.Append("验证失败:\r\n");
foreach (var error in dataErrors)
{
sb.Append(error + "\r\n");
}
MessageBox.Show(sb.ToString());
}
});
}
/// <summary>
/// 页面提交命令
/// </summary>
public RelayCommand SaveCommand { get; set; }
private string userName;
/// <summary>
/// 用户名
/// </summary>
[Required]
public string UserName
{
get { return userName; }
set { userName = value; RaisePropertyChanged(); }
}
private String userEmail;
/// <summary>
/// 用户邮件
/// </summary>
[Required]
[StringLength(100, MinimumLength = 2)]
[RegularExpression("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$", ErrorMessage = "邮箱地址填写错误。")]
public String UserEmail
{
get { return userEmail; }
set { userEmail = value; }
}
/// <summary>
/// 错误集合
/// </summary>
private Dictionary<string, string> dataErrors = new Dictionary<string, string>();
//IDataErrorInfo的固定实现
public string Error
{
get;
}
public string this[string columnName]
{
get
{
ValidationContext 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 (res.Count > 0)
{
string error = string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray());
AddDic(dataErrors, vc.MemberName, error);
return error;
}
RemoveDic(dataErrors, vc.MemberName);
return null;
}
}
/// <summary>
/// 移除错误信息
/// </summary>
/// <param name="dics"></param>
/// <param name="dicKey"></param>
private void RemoveDic(Dictionary<string, string> dics, string dicKey)
{
dics.Remove(dicKey);
}
/// <summary>
/// 添加错误信息
/// </summary>
/// <param name="dics"></param>
/// <param name="dicKey"></param>
private void AddDic(Dictionary<string, string> dics, string dicKey,string dicValue)
{
if(dics.ContainsKey(dicKey))
{
dics.Remove(dicKey);
dics.Add(dicKey, dicValue);
}
else
dics.Add(dicKey, dicValue);
}
}
}
3、在 View 中对需要验证的元素的 Binding 开启属性 :ValidatesOnDataErrors=True
<TextBox
Text="{Binding UserEmail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Width="200"
Height="30" />
完整的 View 代码如下:
<Window
x:Class="IDataErrorInfoDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IDataErrorInfoDemo"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<Label
Content="用户名:"
Margin="0,0,10,0"
FontSize="20" />
<TextBox
Text="{Binding UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Width="200"
Height="30" />
</StackPanel>
<StackPanel Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<Label
Content="邮箱:"
Margin="0,0,10,0"
FontSize="20" />
<TextBox
Text="{Binding UserEmail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Width="200"
Height="30" />
</StackPanel>
<Button Grid.Row="2"
Content="提交"
Command="{Binding SaveCommand}"
Width="200"
Height="30"
Margin="0,20,0,0" />
</Grid>
</Window>