c# - 获取验证结果

标签 c# wpf validation enterprise-library

我正在使用 EntLib 6 验证 block 与 WPF 集成。 我的 VM 中的简单属性:

    [StringLengthValidator(3, MessageTemplate = "Shorten me!")]
    public String SomeText
    {
        get { return _someText; }
        set
        {
            _someText = value;
            OnPropertyChanged("SomeText");
        }
    }

和相应的文本框绑定(bind):

<TextBox ToolTip="{Binding (Validation.Errors).CurrentItem.ErrorContent, RelativeSource={x:Static RelativeSource.Self}}" 
         Text="{Binding SomeText, UpdateSourceTrigger=PropertyChanged}" 
         vab:Validate.BindingForProperty="Text"/>

如果您在 TextBox 中输入了三个以上的字符,该值将被拒绝并存储最后一个有效的字符。 TextBox 以红色突出显示,相应的消息显示为 ToolTip。

在 VM 中,我想检查是否存在任何验证错误 - 但由于该值在 View 中被拒绝,所以一切似乎都很好。那么如何确定是否存在验证错误?

注意:VAB 不使用IDataErrorInfo 接口(interface)!

最佳答案

当您使用 WPF 的内置验证 API 时,我不知道有什么干净直接的方法可以从您的 View 模型中获取验证结果。然而,虽然 VAB 可能不会立即使用 IDataErrorInfo,但您可以相当轻松地添加集成,并且您只需要修改基本 View 模型类。你可以从这样的事情开始:

public class ValidatingModel : INotifyPropertyChanged, IDataErrorInfo
{
    private readonly Dictionary<string, PropertyInfo> _properties;
    private readonly Dictionary<string, Validator> _propertyValidators;
    private readonly Dictionary<string, ValidationResults> _validationResults;

    private string _compositeMessage;

    public ValidatingModel()
    {
        _properties = new Dictionary<string, PropertyInfo>();
        _propertyValidators = new Dictionary<string, Validator>();
        _validationResults = new Dictionary<string, ValidationResults>();

        PopulateValidators();
    }

    private void PopulateValidators()
    {
        var properties = GetType().GetProperties(
            BindingFlags.Instance |
            BindingFlags.Public);

        foreach (var property in properties)
        {
            var attributes = property.GetCustomAttributes(
                typeof(ValueValidatorAttribute),
                false);

            if (attributes.Length == 0 || _properties.ContainsKey(property.Name))
                continue;

            _properties[property.Name] = property;

            _propertyValidators[property.Name] =
                PropertyValidationFactory.GetPropertyValidatorFromAttributes(
                    property.PropertyType,
                    property,
                    string.Empty,
                    new MemberAccessValidatorBuilderFactory());
        }
    }

    protected IEnumerable<ValidationResult> GetValidationResults()
    {
        foreach (var results in _validationResults.Values)
        {
            foreach (var result in results)
                yield return result;
        }
    }

    protected IEnumerable<ValidationResult> GetValidationResults(string property)
    {
        if (_propertyValidators.ContainsKey(property))
        {
            ValidationResults results;

            if (!_validationResults.TryGetValue(property, out results))
                Validate(property);

            if (!_validationResults.TryGetValue(property, out results))
                yield break;

            foreach (var result in results)
                yield return result;
        }
    }

    protected void Validate(string propertyName)
    {
        if (_propertyValidators.ContainsKey(propertyName))
        {
            _compositeMessage = null;
            _validationResults[propertyName] = Validation.Validate(this);
        }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            ValidationResults results;

            if (!_validationResults.TryGetValue(columnName, out results))
                Validate(columnName);

            if (_validationResults.TryGetValue(columnName, out results))
                return CombineMessages(results);

            return null;
        }
    }

    string IDataErrorInfo.Error
    {
        get
        {
            if (_compositeMessage != null)
                return _compositeMessage;

            foreach (var validator in _propertyValidators)
            {
                if (_validationResults.ContainsKey(validator.Key))
                    continue;

                _validationResults[validator.Key] = ValidateProperty(
                    validator.Value,
                    _properties[validator.Key]);
            }

            _compositeMessage = CombineMessages(
                _validationResults.SelectMany(r => r.Value));

            return _compositeMessage;
        }
    }

    private ValidationResults ValidateProperty(
        Validator validator,
        PropertyInfo propertyInfo)
    {
        return validator.Validate(propertyInfo.GetValue(this, null));
    }

    private static string CombineMessages(IEnumerable<ValidationResult> results)
    {
        return results.Aggregate(
            new StringBuilder(),
            (sb, p) => (sb.Length > 0 ? sb.AppendLine() : sb).Append(p.Message),
            sb => sb.ToString());
    }

    protected void OnPropertyChanged(string propertyName)
    {
        Validate(propertyName);

        var handler = this.PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

只要属性发生变化,此 View 模型就会使用验证应用程序 block API 执行验证,并通过 IDataErrorInfo 报告结果。您需要在 Binding 声明中设置 ValidatesOnDataErrors 才能使其正常工作。

关于c# - 获取验证结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27061980/

相关文章:

c# - inlineShape = inlineShapes.AddPicture() ;引用任何 word 文件,而不是我创建的 Interop.Word.Application

c# - 动态创建 <Type> 的对象

MVVM 中的 WPF 数据绑定(bind) Image.Source

c# - Caliburn.Micro Binding 似乎无法在 View 模型中解析

validation - 在不使用 ngSubmit 的情况下进行 Angular 表单验证

forms - 如何在 Play 中同时验证多个表单字段?

c# - ASP.NET MVC 5 - 身份。如何获取当前的ApplicationUser

c# - 如何从 WPF Extended Toolkit 正确实现 Busy Indicator

JavaScript:检查日期 A 是否比日期 B 最多早/晚 3 倍

c# - 用户控件的项目集合选项