如何在加载时禁用IDataErrorInfo和DataAnnotations验证

问题描述 投票:0回答:2

我正在使用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
2个回答
2
投票

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

  1. Foreach属性创建另一个布尔字段或字典条目以指示是否应该验证属性。在每个属性的setter中,将字段设置为true。如果尚未设置该属性,则不返回错误。您还需要验证方法,它将验证所有属性。
  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; }
    }
}

}


0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.