1

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

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

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

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

4

1 回答 1

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);
    }
}
于 2018-10-08T06:44:22.823 回答