WPF如何手动设置控件上的Validation.HasError属性?

时间:2018-10-02 21:43:37

标签: wpf inotifydataerrorinfo

我有一个wpf窗口,当用户与控件进行交互(进入控件并更改导致更新的属性的值)时,该窗口会触发验证,并在属性更改时触发验证并按应有的方式显示。

但是我想在用户单击保存按钮而不遍历控件时在屏幕上手动显示所有验证错误,否则,如果用户加载屏幕并单击保存按钮,应该如何显示?

即使我创建了一个类似IsValid()的方法并在单击保存按钮时调用它,它也会验证整个表单并告诉我它是否有效,但是文本框周围的红色边框不会显示(因为Validation.HasError属性未更新),这是我需要的,因为它的形式为几种 控件,我需要通知用户引起问题的确切控件。

您可以从此链接获取有问题的示例项目 https://1drv.ms/u/s!AuCr-YEWkmWUiopdQ-eZ17IC7IAJnA

1 个答案:

答案 0 :(得分:3)

当我们验证属性而不遍历它时。它不会更新控件的Validate.HasError属性。解决方案是使用简单的老式NotifyPropertyChanged(propertyName)。

当我的属性值更改(在集合中)但没有遍历它时,我一直在使用NotifyPropertyChanged,它从不触发。

因此,要么在属性验证失败时调用NotifyPropertyChanged,要么调用NotifyPropertyChanged(null),通知所有控件刷新其属性。

添加我的INotifyDataErrorInfo的完整实现

    public class NotifyDataErrorInfoBase<T> : INotifyDataErrorInfo
{
    public NotifyDataErrorInfoBase(T model)
    {
        Model = model;
    }

    public T Model { get; set; }

    protected void SetValue<TValue>(string propertyName, TValue value)
    {
        typeof(T).GetProperty(propertyName).SetValue(Model, value);
        ValidateProperty<TValue>(propertyName);
    }

    public bool ValidateAllProperties()
    {

        List<KeyValuePair<string, Type>> lstOfProperties = typeof(T).GetProperties().
             Select(u => new KeyValuePair<string, Type>(u.Name, u.PropertyType)).ToList();
        foreach (var property in lstOfProperties)
        {
           Type currentType = property.Value;
            if (property.Value == typeof(string))
            {
                ValidateProperty<string>(property.Key);
            }
            else if (property.Value == typeof(int))
            {
                ValidateProperty<int>(property.Key);
            }
        }
        return !HasErrors;
    }

    private void ValidateProperty<TValue>([CallerMemberName]string propertyName = null)
    {
        ClearErrors(propertyName);
        var validationContext = new ValidationContext(Model) { MemberName = propertyName };
        List<ValidationResult> results = new List<ValidationResult>();

        var userName = GetValue<TValue>(propertyName);
        Validator.TryValidateProperty(userName, validationContext, results);

        if (results.Any())
        {
            foreach (var item in results)
            {
                AddError(propertyName, item.ErrorMessage);
            }
        }
    }

    protected TValue GetValue<TValue>(string propertyName)
    {
        return (TValue)typeof(T).GetProperty(propertyName).GetValue(Model);
    }

    Dictionary<string, List<string>> _lstOfErrors = new Dictionary<string, List<string>>();

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public bool HasErrors => _lstOfErrors.Any();

    public IEnumerable GetErrors(string propertyName)
    {
        return _lstOfErrors.ContainsKey(propertyName) ? _lstOfErrors[propertyName] : null;
    }

    protected void AddError(string propertyName, string errorMessage)
    {
        if (!_lstOfErrors.ContainsKey(propertyName))
        {
            _lstOfErrors[propertyName] = new List<string>();
        }
        _lstOfErrors[propertyName].Add(errorMessage);
    }

    protected void OnErrorsChanged(string propertyName)
    {
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    }

    protected void ClearErrors(string propertyName)
    {
        if (_lstOfErrors.ContainsKey(propertyName))
            _lstOfErrors.Remove(propertyName);
    }
}