Combining DataAnnotations and IDataErrorInfo for WPF

跟風遠走 提交于 2019-12-05 11:26:18

Using your above code as a starting point I got this working through IDataErrorInfo.

Your problem centred around getting the value of the property when you only have the property name, reflection can help here.

public string this[string property]
{
   get
   {
      PropertyInfo propertyInfo = this.GetType().GetProperty(property);
      var results = new List<ValidationResult>();

      var result = Validator.TryValidateProperty(
                                propertyInfo.GetValue(this, null),
                                new ValidationContext(this, null, null)
                                {
                                  MemberName = property
                                }, 
                                results);

      if (!result)
      {
        var validationResult = results.First();
        return validationResult.ErrorMessage;
      }

      return string.Empty;
   }
}

I know this post is old, but I recently solved this problem with help from this post, while making some optimizations along the way. I'd like to share my ViewModelBase's implementation of IDataErrorInfo. It uses compiled expressions for the property getters which speeds the property value access. I also fire off the expression compilations on background thread when the type is loaded into memory. Hopefully, it finishes compilation before the first call to OnValidate since expression compilation can be a bit slow. Thanks and cheers.

public abstract class ViewModelBase<TViewModel> : IDataErrorInfo
    where TViewModel : ViewModelBase<TViewModel>
{
    string IDataErrorInfo.Error
    { 
        get { throw new NotSupportedException("IDataErrorInfo.Error is not supported, use IDataErrorInfo.this[propertyName] instead."); } 
    } 

    string IDataErrorInfo.this[string propertyName] 
    {
        get { return OnValidate(propertyName, propertyGetters.Result[propertyName]((TViewModel)this)); } 
    }

    private static Task<Dictionary<string, Func<TViewModel, object>>> propertyGetters = Task.Run(() =>
    {
        return typeof(TViewModel).GetProperties()
            .Select(propertyInfo =>
            {
                var viewModel = Expression.Parameter(typeof(TViewModel));
                var property = Expression.Property(viewModel, propertyInfo);
                var castToObject = Expression.Convert(property, typeof(object));
                var lambda = Expression.Lambda(castToObject, viewModel);

                return new
                {
                    Key = propertyInfo.Name,
                    Value = (Func<TViewModel, object>)lambda.Compile()
                };
            })
            .ToDictionary(pair => pair.Key, pair => pair.Value);
    });

    protected virtual string OnValidate(string propertyName, object propertyValue)
    {
        var validationResults = new List<ValidationResult>();

        var validationContext = new ValidationContext(this, null, null) { MemberName = propertyName };

        if (!Validator.TryValidateProperty(propertyValue, validationContext, validationResults))
        {
            return validationResults.First().ErrorMessage;
        }

        return string.Empty;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!