在WPF应用程序开发中,数据验证是一个重要的环节。本文将介绍如何利用属性和接口实现条件验证,确保用户输入满足特定条件。
WPF提供了多种数据验证方法,本文将展示如何通过实现IDataErrorInfo
接口和扩展RangeAttribute
来实现条件验证。
条件验证指的是在某些条件下才触发的验证。例如,只有当用户勾选了某个复选框时,才需要验证另一个输入框的值。
首先,需要扩展RangeAttribute
来支持条件验证。以下是RangeIfAttribute
类的实现:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
[Conditional]
public class RangeIfAttribute : RangeAttribute
{
private string _dependentProperty;
public RangeIfAttribute(double minimum, double maximum, string dependentProperty)
: base(minimum, maximum)
{
this._dependentProperty = dependentProperty;
}
public RangeIfAttribute(int minimum, int maximum, string dependentProperty)
: base(minimum, maximum)
{
this._dependentProperty = dependentProperty;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var containerType = validationContext.ObjectInstance.GetType();
var field = containerType.GetProperty(this._dependentProperty);
bool dependentvalue = (bool)field.GetValue(validationContext.ObjectInstance);
if (dependentvalue)
{
return base.IsValid(value, validationContext);
}
return ValidationResult.Success;
}
}
这个类通过重写IsValid
方法,实现了条件验证逻辑。
接下来,在ViewModel中使用RangeIfAttribute
来装饰属性:
public class CandidateViewModel : ViewModelBase
{
private int _yearsOfExperience;
private bool _isExperienced;
[RangeIf(1, 100, "IsExperienced", ErrorMessage = "Years Of Experience must be greater than 0")]
public int YearsOfExperience
{
get { return this._yearsOfExperience; }
set { this._yearsOfExperience = value; }
}
public bool IsExperienced
{
get { return this._isExperienced; }
set { this._isExperienced = value; this.OnPropertyChanged("YearsOfExperience"); }
}
}
这里,YearsOfExperience
属性依赖于IsExperienced
属性的值。只有当IsExperienced
为true时,YearsOfExperience
的值才需要在1到100之间。
为了支持条件验证,需要在ViewModelBase类中实现IDataErrorInfo
接口:
public class ViewModelBase : IDataErrorInfo, INotifyPropertyChanged
{
private readonly Dictionary> propertyGetters;
private readonly Dictionary validators;
public ViewModelBase()
{
this.validators = this.GetType().GetProperties()
.Where(p => this.GetValidations(p).Length != 0)
.ToDictionary(p => p.Name, p => this.GetValidations(p));
this.propertyGetters = this.GetType().GetProperties()
.Where(p => this.GetValidations(p).Length != 0)
.ToDictionary(p => p.Name, p => this.GetValueGetter(p));
}
public string this[string propertyName]
{
get
{
if (this.propertyGetters.ContainsKey(propertyName))
{
var errorMessages = this.validators[propertyName]
.Where(attribute => !this.Validate(attribute, propertyName))
.Select(attribute => attribute.ErrorMessage).ToList();
return string.Join(Environment.NewLine, errorMessages);
}
return string.Empty;
}
}
private bool Validate(ValidationAttribute validationAttribute, string propertyName)
{
var propertyValue = this.propertyGetters[propertyName](this);
if (IsConditionalValidationAttribute(validationAttribute))
{
return validationAttribute.GetValidationResult(propertyValue, new ValidationContext(this)) == ValidationResult.Success;
}
return validationAttribute.IsValid(propertyValue);
}
private bool IsConditionalValidationAttribute(ValidationAttribute validationAttribute)
{
return validationAttribute.GetType().GetCustomAttributes().Any(x => x.GetType() == typeof(ConditionalAttribute));
}
}
在这个类中,通过重写索引器来获取属性的验证错误信息。如果验证属性是条件验证属性,调用GetValidationResult
方法来获取验证结果。
本文介绍了如何在WPF应用程序中实现条件验证。通过扩展RangeAttribute
和实现IDataErrorInfo
接口,可以轻松地为应用程序添加条件验证逻辑。这种方法不仅清晰,而且易于维护。