【问题标题】:How do I disable IDataErrorInfo & DataAnnotations Validation on load如何在加载时禁用 IDataErrorInfo 和 DataAnnotations 验证
【发布时间】:2015-03-24 09:15:52
【问题描述】:

我正在使用 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?

非常感谢!!

【问题讨论】:

  • @我会知道,但怎么知道?

标签: c# wpf validation mvvm


【解决方案1】:

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

  1. Foreach 属性创建另一个布尔字段或字典条目以指示是否应验证该属性。在每个属性的 setter 中,将字段设置为 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; }
    }
}

}

【讨论】:

    【解决方案2】:

    在基本视图模型中实现 INotifyDataErrorInfo 并添加 isValidating bool 字段。在您的 GetErrors(string propName) 实现中,首先检查 isValidating 并在为 false 时提前返回。

    您还应该添加一个 Validate() 方法,将 isValidating 设置为 true 并使用 Validator.TryValidateObject() 启动完整的对象验证。当用户单击 OK 时调用 Validate(),然后所有属性修改都将更新验证。

    【讨论】:

      猜你喜欢
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-27
      相关资源
      最近更新 更多