(转)Silverlight数据校验之INotifyDataErrorInfo
原文地址:http://www.cnblogs.com/PerfectSoft/archive/2012/03/01/2375007.html
在Silverlight中,数据实体类的有效性校验有多种方法,比如说:运用TargetNullValue、FailBackValue、ValidatesOnExceptions.....,运用这些方法可以解决常见的问题,但是针对一些复杂性的数据校验,显然不是最有效的利器。比如说:在针对单个属性进行多重有效性验证的情况下,此时,可以灵活的运用INotifyDataErrorInfo接口。
MSDN INotifyDataErrorInfor的定义如下:
// Summary:
// Defines members that data entity classes can implement to provide custom,
// asynchronous validation support.
public interface INotifyDataErrorInfo
{
// Summary:
// Gets a value that indicates whether the object has validation errors.
//
// Returns:
// true if the object currently has validation errors; otherwise, false.
bool HasErrors { get; }
// Summary:
// Occurs when the validation errors have changed for a property or for the
// entire object.
event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
// Summary:
// Gets the validation errors for a specified property or for the entire object.
//
// Parameters:
// propertyName:
// The name of the property to retrieve validation errors for, or null or System.String.Empty
// to retrieve errors for the entire object.
//
// Returns:
// The validation errors for the property or object.
IEnumerable GetErrors(string propertyName);
}
从INotifyDataErrorInfo的定义,就能够了解到它的作用。数据实体类可以继承INotifyDataErrorInfo,实现满足业务需求的有效性校验。下面以Student实体类实现INotifyDataErrorInfo接口为例。
Student定义:
public class Student : INotifyPropertyChanged,INotifyDataErrorInfo
{
//存放错误信息,一个Property可能对应多个错误信息
private Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
//实现INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
//实现INotifyDataErrorInfo
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
return null;
}
else
{
if (errors.ContainsKey(propertyName))
{
return errors[propertyName];
}
}
return null;
}
public bool HasErrors
{
get
{
return (errors.Count > 0);
}
}
private void SetErrors(string propertyName, List<string> propertyErrors)
{
errors.Remove(propertyName);
errors.Add(propertyName, propertyErrors);
if (ErrorsChanged != null)
{
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
private void ClearErrors(string propertyName)
{
errors.Remove(propertyName);
if (ErrorsChanged != null)
{
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
private string name;
private int age;
public String Name
{
get
{
return name;
}
set
{
name = value;
List<string> errors = new List<string>();
bool valid = true;
//数据校验
if (name.Trim().Contains(" "))
{
errors.Add("姓名中不能包含空格");
valid = false;
}
if (name.Length < 2 || name.Length > 4)
{
errors.Add("姓名的长度不能低于2高于4");
valid = false;
}
if (!valid)
{
SetErrors("Name", errors);
}
else
{
ClearErrors("Name");
}
}
}
public int Age
{
get
{
return age;
}
set
{
age = value;
if (age < 0 || age > 150)
{
List<string> errors = new List<string>();
errors.Add("年龄不能小于0或大于150");
SetErrors("Age", errors);
}
else
{
ClearErrors("Age");
}
}
}
}
在MainPage XAML代码中,执行数据绑定时,必须设置ValidatesOnNotifyDataErrors = True。
<Grid x:Name="LayoutRoot" Background="White" BindingValidationError="LayoutRoot_BindingValidationError">
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="姓名:" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
<TextBox x:Name="txtName" Text="{Binding Name, Mode=TwoWay, ValidatesOnExceptions=True,
ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" Width="150" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center">
</TextBox>
<TextBlock Text="年龄:" HorizontalAlignment="Right" Grid.Row="1" VerticalAlignment="Center"></TextBlock>
<TextBox x:Name="txtAge" Text="{Binding Age, Mode=TwoWay, ValidatesOnExceptions=True,
ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" Width="150" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center">
</TextBox>
<Button x:Name="Submit" Content="Submit The Data" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="1" Click="Submit_Click" VerticalAlignment="Center"></Button>
<TextBlock x:Name="Summary" Text="无任何错误信息" VerticalAlignment="Center" Grid.Column="1" Grid.Row="3"></TextBlock>
</Grid>
MainPage 后台代码:
public MainPage()
{
InitializeComponent();
Student product = new Student();
LayoutRoot.DataContext = product;
}
private void LayoutRoot_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
//可能没有Exception,但是存在错误信息
if (e.Error.Exception != null)
{
//异常处理代码
}
else
{
Summary.Text = e.Error.ErrorContent.ToString();
txtName.Focus();
}
}
运行结果:
如果要实现复杂的数据验证,INotifyDataErrorInfo也是一个不错的选择,有不足之处,请大家指出。