[英]How to do a simple validation with IDataErrorInfo and data annotations
[英]How do I disable IDataErrorInfo & DataAnnotations Validation on load
我正在使用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?
非常感謝你!!
這總是有點棘手。 有兩種方法:
這是示例:
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; }
}
}
}
在基本視圖模型中實現INotifyDataErrorInfo並添加一個isValidating bool字段。 在您的GetErrors(string propName)實現中,首先檢查isValidating,如果為false則提早返回。
您還應該添加一個Validate()方法,該方法將isValidating設置為true並使用Validator.TryValidateObject()啟動完整的對象驗證。 當用戶單擊“確定”時,調用Validate(),然后所有屬性修改將更新驗證。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.