如何禁用IDataErrorInfo& DataAnnotations对负载进行验证

时间:2015-03-24 09:15:53

标签: c# wpf validation mvvm

我正在使用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验证。因此,应用程序将立即打开窗口时指出空白错误。像这样: The View

当一次打开窗口时,应用程序如何跳过验证属性?另一种方法,单击提交按钮时,应用程序如何验证RequiredAttribute?

非常感谢!!

2 个答案:

答案 0 :(得分:2)

这总是有点棘手。有两种方法:

  1. Foreach属性创建另一个布尔字段或字典条目以指示是否应验证属性。在每个属性的setter中,将字段设置为true。如果尚未设置该属性,则不返回错误。您还需要验证方法,它将验证所有属性。
  2. 使用INotifyDataErrorInfo,在发生错误时通知视图:
  3. 这里是例子:

    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(),然后所有属性修改将更新验证。