棱镜IDataErrorInfo的验证与视图模型实体DataAnnotation [英] Prism IDataErrorInfo validation with DataAnnotation on ViewModel Entities

查看:148
本文介绍了棱镜IDataErrorInfo的验证与视图模型实体DataAnnotation的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实施使用Prism MVVM框架WPF数据验证。我使用这些被绑定到表现层中的视图模型干净的数据实体

 <文本框的文本={结合User.Email,ValidatesOnDataErrors = TRUE,UpdateSourceTrigger =的PropertyChanged}/> 



我已经实现了一个通用实现IDataErrorInfo的在运行验证对DataAnnotation属性的基础ViewModel类在我的实体(在这种情况下,用户)。



问题是绑定到一个实体时,WPF框架查找IDataErrorInfo的实体上,而不是在ViewModel这是我想这样的逻辑存在。如果我总结我的实体,在我的ViewModel然后一切正常属性,但我不希望危及使用视图模型中的实体。



有没有办法来告诉WPF来寻找IDataErrorInfo的在视图模型,而不是一个子对象的绑定?



谢谢,
迈克


< DIV CLASS =h2_lin>解决方案

我去的选择是在一个由所有的ViewModels和实体扩展一个基类明确实现IDataErrorInfo的。这似乎是最好的折衷办法得到的东西空转与WPF,并且至少保持IDataErrorInfo的隐藏呼叫者所以他们至少出现干净的实施。我露出一个受保护的ValidateProperty可以根据需要在任何自定义行为的子类(如密码/ PasswordConfirmation情景)所覆盖。

 公共抽象类DataErrorInfo:IDataErrorInfo的
{
串IDataErrorInfo.Error
{
{返回NULL; }
}

串IDataErrorInfo.this [字符串COLUMNNAME]
{
{返回ValidateProperty(COLUMNNAME); }
}

受保护的虚拟串ValidateProperty(字符串COLUMNNAME)
{
//获取缓存属性访问
VAR propertyGetters = GetPropertyGetterLookups(的GetType()) ;

如果(propertyGetters.ContainsKey(COLUMNNAME))
{
//读取指定属性
VAR值的值= propertyGetters [COLUMNNAME](本);

//运行验证
变种结果=新的List<&为ValidationResult GT;();
变种VC =新ValidationContext(本,NULL,NULL){MemberName = COLUMNNAME};
Validator.TryValidateProperty(价值,VC,结果);

//调换结果
VAR误差= Array.ConvertAll(results.ToArray(),O => o.ErrorMessage);
返回的string.join(Environment.NewLine,错误);
}
返回的String.Empty;
}

私人静态只读字典<字符串对象> PropertyLookupCache =
新字典<字符串对象>();

私有静态字典<字符串函数功能:LT;对象,对象>> GetPropertyGetterLookups(类型OBJTYPE)
{
VAR键= objType.FullName? ;
如果
{
变种O = objType.GetProperties()
。凡(P =>(PropertyLookupCache.ContainsKey(密钥)!);!GetValidations(P)。长度= 0)
.ToDictionary(p => p.Name,CreatePropertyGetter);

PropertyLookupCache [关键] = O;
返回O;
}
返回(词典<字符串函数功能:LT;对象,对象>>)PropertyLookupCache [关键]
}

私有静态Func键<对象,对象> CreatePropertyGetter(的PropertyInfo的PropertyInfo)
{
VAR instanceParameter = Expression.Parameter(typeof运算(对象),实例);

VAR表达式= Expression.Lambda<&Func键LT;对象,对象>>(
Expression.ConvertChecked(
Expression.MakeMemberAccess(
Expression.ConvertChecked(instanceParameter, propertyInfo.DeclaringType),
的PropertyInfo),
的typeof(对象)),
instanceParameter);

VAR compiledExpression = expression.Compile();

返回compiledExpression;
}

私有静态ValidationAttribute [] GetValidations(的PropertyInfo财产)
{
回报率(ValidationAttribute [])property.GetCustomAttributes(typeof运算(ValidationAttribute),TRUE);
}


}


I'm implementing data validation in WPF using the Prism MVVM framework. I'm using clean data Entities in the ViewModel which are being bound to the presentation layer.

 <TextBox Text="{Binding User.Email, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />

I've implemented a generic implementation of IDataErrorInfo in a base ViewModel class that runs validation against the DataAnnotation attributes on my Entity (in this case User).

The issue is that when binding to an Entity, the WPF framework looks for IDataErrorInfo on the Entity and not the ViewModel which is where I want this logic to exist. If I wrap my Entity with properties in my ViewModel then everything works, but I don't wish to compromise the use of Entities within the ViewModel.

Is there a way to tell WPF to look for the IDataErrorInfo in the ViewModel and not a child object that's being bound?

Thanks, Mike

解决方案

The option I went with was to implement IDataErrorInfo explicitly in a base class which is extended by all ViewModels and Entities. This seems the best compromise to get things ticking over with WPF, and at least keeps the implementation of IDataErrorInfo hidden to callers so they at least appear clean. I expose a protected ValidateProperty which can be overridden if necessary in subclasses for any custom behaviour (such as for Password/PasswordConfirmation scenario).

public abstract class DataErrorInfo : IDataErrorInfo
{
    string IDataErrorInfo.Error
    {
        get { return null; }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get { return ValidateProperty(columnName); }
    }

    protected virtual string ValidateProperty(string columnName)
    {
         // get cached property accessors
            var propertyGetters = GetPropertyGetterLookups(GetType());

            if (propertyGetters.ContainsKey(columnName))
            {
                // read value of given property
                var value = propertyGetters[columnName](this);

                // run validation
                var results = new List<ValidationResult>();
                var vc = new ValidationContext(this, null, null) { MemberName = columnName };
                Validator.TryValidateProperty(value, vc, results);

                // transpose results
                var errors = Array.ConvertAll(results.ToArray(), o => o.ErrorMessage);
                return string.Join(Environment.NewLine, errors);
            }
            return string.Empty;
    }

    private static readonly Dictionary<string, object> PropertyLookupCache =
        new Dictionary<string, object>();

    private static Dictionary<string, Func<object, object>> GetPropertyGetterLookups(Type objType)
    {
        var key = objType.FullName ?? "";
        if (!PropertyLookupCache.ContainsKey(key))
        {
            var o = objType.GetProperties()
            .Where(p => GetValidations(p).Length != 0)
            .ToDictionary(p => p.Name, CreatePropertyGetter);

            PropertyLookupCache[key] = o;
            return o;
        }
        return (Dictionary<string, Func<object, object>>)PropertyLookupCache[key];
    }

    private static Func<object, object> CreatePropertyGetter(PropertyInfo propertyInfo)
    {
        var instanceParameter = Expression.Parameter(typeof(object), "instance");

        var expression = Expression.Lambda<Func<object, object>>(
            Expression.ConvertChecked(
                Expression.MakeMemberAccess(
                    Expression.ConvertChecked(instanceParameter, propertyInfo.DeclaringType),
                    propertyInfo),
                typeof(object)),
            instanceParameter);

        var compiledExpression = expression.Compile();

        return compiledExpression;
    }

    private static ValidationAttribute[] GetValidations(PropertyInfo property)
    {
        return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true);
    }


}

这篇关于棱镜IDataErrorInfo的验证与视图模型实体DataAnnotation的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆