簡體   English   中英

如何在加載時禁用IDataErrorInfo和DataAnnotations驗證

[英]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?

非常感謝你!!

這總是有點棘手。 有兩種方法:

  1. Foreach屬性創建另一個布爾字段或字典條目以指示是否應驗證該屬性。 在每個屬性的設置器中,將字段設置為true。 如果尚未設置該屬性,則不返回錯誤。 您還將需要validate方法,該方法將驗證所有屬性。
  2. 使用INotifyDataErrorInfo,在發生錯誤時通知視圖:

這是示例:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM