我正在使用MVVM方法编写WPF应用程序,我使用IDataErrorInfo和DataAnnotations来验证输入数据。就像这样:
视图模型
/// <summary>
/// User
/// </summary>
[Required(ErrorMessage = "not blank")]
[StringLength(20, MinimumLength = 6, ErrorMessage = "between 6 and 20")]
public string UserID
{
get
{
return _adminInfoModel.UserID;
}
set
{
if (_adminInfoModel.UserID != value)
{
_adminInfoModel.UserID = value;
OnPropertyChanged("UserID");
}
}
}
/// <summary>
/// Name
/// </summary>
[Required(ErrorMessage = "not blank")]
[StringLength(100, ErrorMessage = "less than 100 character")]
public string Name
{
get
{
return _adminInfoModel.Name;
}
set
{
if (_adminInfoModel.Name != value)
{
_adminInfoModel.Name = value;
OnPropertyChanged("Name");
}
}
}
//many properties here....
//implement the IDataErrorInfo interface
public string this[string columnName]
{
get
{
ValidationContext vc = new ValidationContext(this, null, null);
vc.MemberName = columnName;
List<ValidationResult> results = new List<ValidationResult>();
bool result = Validator.TryValidateProperty(this.GetType().GetProperty(columnName).GetValue(this, null), vc, results);
if (results.Count > 0)
{
return results[0].ErrorMessage;
}
return string.Empty;
}
}
查看:
<TextBox Name="UserIDTB" Text="{Binding UserID, UpdateSourceTrigger=LostFocus, Mode=TwoWay, ValidatesOnDataErrors=True}" />
<TextBox Name="NameTB" Text="{Binding Name, ValidatesOnDataErrors=True}" />
问题是:
当我打开此视图时,由于ViewModel实现了IDataErrorInfo接口,因此应用程序将立即验证属性。某些属性使用RequiredAttribute验证。因此,应用程序将立即打开窗口时指出空白错误。像这样:
当一次打开窗口时,应用程序如何跳过验证属性?另一种方法,单击提交按钮时,应用程序如何验证RequiredAttribute?
非常感谢!!
答案 0 :(得分:2)
这总是有点棘手。有两种方法:
这里是例子:
public class MyViewModel : ValidatableBase
{
[Required]
public string SomeProperty
{
get { return _someProperty; }
set { SetProperty(ref _someProperty, value); }
}
}
public abstract class ValidatableBase : BindableBase, INotifyDataErrorInfo
{
private readonly Dictionary<string, string> _propertyErrors = new Dictionary<string, string>();
protected override bool SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
var result = base.SetProperty(ref storage, value, propertyName);
var error = ValidateProperty(propertyName, value);
SetError(propertyName, error);
return result;
}
private void SetError(string propertyName, string error, bool notify = false)
{
string existingError;
_propertyErrors.TryGetValue(propertyName, out existingError);
if (error == null)
{
if (existingError != null) _propertyErrors.Remove(propertyName);
}
else
{
_propertyErrors[propertyName] = error;
}
if (existingError != error)
{
OnErrorsChanged(propertyName);
}
}
public virtual bool Validate()
{
var properties = TypeDescriptor.GetProperties(this);
foreach (PropertyDescriptor property in properties)
{
var error = ValidateProperty(property.Name, property.GetValue(this));
SetError(property.Name, error, true);
}
return HasErrors;
}
public void Validate(string propertyName, object value)
{
var error = ValidateProperty(propertyName, value);
SetError(propertyName, error, true);
}
protected virtual string ValidateProperty(string propertyName, object value)
{
if (propertyName == null) throw new ArgumentNullException("propertyName");
var validationContext = new ValidationContext(this);
validationContext.MemberName = propertyName;
var validationResults = new List<ValidationResult>();
if (Validator.TryValidateProperty(value, validationContext, validationResults))
{
return null;
}
return validationResults[0].ErrorMessage;
}
protected virtual void OnErrorsChanged(string propertyName)
{
var handler = ErrorsChanged;
if (handler != null) handler(this, new DataErrorsChangedEventArgs(propertyName));
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public System.Collections.IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName)) yield break;
string existingError;
if (_propertyErrors.TryGetValue(propertyName, out existingError))
{
yield return existingError;
}
}
public bool HasErrors
{
get { return _propertyErrors.Count > 0; }
}
}
}
答案 1 :(得分:0)
在基本视图模型中实现INotifyDataErrorInfo并添加isValidating bool字段。在您的GetErrors(string propName)实现中,首先检查isValidating,如果为false则提早返回。
您还应该添加一个Validate()方法,该方法将isValidating设置为true,并使用Validator.TryValidateObject()启动完整的对象验证。当用户单击“确定”时,调用Validate(),然后所有属性修改将更新验证。