使用DataAnnotations在WPF和Entity Framework中验证数据?

36

在WPF和Entity Framework中,有没有使用DataAnnotations进行验证的方法?

7个回答

48
您可以使用DataAnnotations.Validator类,如此处所述:

http://johan.driessen.se/archive/2009/11/18/testing-dataannotation-based-validation-in-asp.net-mvc.aspx

但是如果您在元数据中使用“buddy”类,则需要在验证之前注册该事实,如此处所述:

http://forums.silverlight.net/forums/p/149264/377212.aspx

TypeDescriptor.AddProviderTransparent(
  new AssociatedMetadataTypeTypeDescriptionProvider(typeof(myEntity), 
    typeof(myEntityMetadataClass)), 
  typeof(myEntity));

List<ValidationResult> results = new List<ValidationResult>();
ValidationContext context = new ValidationContext(myEntity, null, null)
bool valid = Validator.TryValidateObject(myEntity, context, results, true);

[针对Shimmy的评论,添加以下内容]

我编写了一个通用的方法来实现上述逻辑,以便任何对象都可以调用它:

// If the class to be validated does not have a separate metadata class, pass
// the same type for both typeparams.
public static bool IsValid<T, U>(this T obj, ref Dictionary<string, string> errors)
{
    //If metadata class type has been passed in that's different from the class to be validated, register the association
    if (typeof(T) != typeof(U))
    {
        TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(T), typeof(U)), typeof(T));
    }

    var validationContext = new ValidationContext(obj, null, null);
    var validationResults = new List<ValidationResult>();
    Validator.TryValidateObject(obj, validationContext, validationResults, true);

    if (validationResults.Count > 0 && errors == null)
        errors = new Dictionary<string, string>(validationResults.Count);

    foreach (var validationResult in validationResults)
    {
        errors.Add(validationResult.MemberNames.First(), validationResult.ErrorMessage);
    }

    if (validationResults.Count > 0)
        return false;
    else
        return true;
}

在需要进行验证的每个对象中,我都会添加对此方法的调用:

[MetadataType(typeof(Employee.Metadata))]
public partial class Employee
{
    private sealed class Metadata
    {
        [DisplayName("Email")]
        [Email(ErrorMessage = "Please enter a valid email address.")]
        public string EmailAddress { get; set; }
    }

    public bool IsValid(ref Dictionary<string, string> errors)
    {
        return this.IsValid<Employee, Metadata>(ref errors);
        //If the Employee class didn't have a buddy class,
        //I'd just pass Employee twice:
        //return this.IsValid<Employee, Employee>(ref errors);
    }
}

我有很多与MD相关的类,你有什么好主意可以动态地将它们与MD关联起来,但我想按需进行,即只有在我使用这个类(或其验证)时才这样做,并且只做一次。 - Shimmy Weitzhandler
顺便说一下,不需要将字典标记为'ref',因为您不会改变引用,只需访问其属性即可。谢谢! - Shimmy Weitzhandler
@Shimmy - 我将错误字典作为'ref'传递,因为IsValid函数会将错误添加到其中(必要时进行初始化),我希望能够随着布尔返回值一起获取结果。 - Jeremy Gruenwald
我知道这有点老了,但这是纯金!+1 - MHollis
1
字典是一种引用类型(而不是值类型),并且始终按引用传递。 - JarrettV
这里有两个对于Silverlight开发人员的重要注意事项。
  1. 此答案中使用的技术在Silverlight中不受支持,因为AssociatedMetadataTypeTypeDescriptionProvider类(和其他类)未实现。 http://jeffhandley.com/archive/2010/11/16/DataAnnotationsSubset.aspx
  2. RIA服务包括将验证属性添加到客户端生成的元数据类中的属性 - 这意味着在使用RIA服务时,在客户端上这不是一个问题。
- Scott Munro

4

我认为克雷格的答案中缺少的是如何检查是否存在验证错误的方法。以下是由Steve Sanderson编写的DataAnnotation验证运行程序,适用于希望在演示层以外的不同层运行验证检查的人(http://blog.codeville.net/category/xval/,代码在示例项目中):

public static IEnumerable<ErrorInfo> GetErrors(object instance)
{
    var metadataAttrib = instance.GetType().GetCustomAttributes
        (typeof(MetadataTypeAttribute), true).
            OfType<MetadataTypeAttribute>().FirstOrDefault();
    var buddyClassOrModelClass = 
        metadataAttrib != null ? 
        metadataAttrib.MetadataClassType : 
        instance.GetType();
    var buddyClassProperties = TypeDescriptor.GetProperties
        (buddyClassOrModelClass).Cast<PropertyDescriptor>();
    var modelClassProperties = TypeDescriptor.GetProperties
        (instance.GetType()).Cast<PropertyDescriptor>();

    return from buddyProp in buddyClassProperties
           join modelProp in modelClassProperties
               on buddyProp.Name equals modelProp.Name
           from attribute in buddyProp.Attributes.
               OfType<ValidationAttribute>()
           where !attribute.IsValid(modelProp.GetValue(instance))
           select new ErrorInfo(buddyProp.Name, 
               attribute.FormatErrorMessage(string.Empty), instance);
}

我不熟悉WPF(不确定是否有适合你问题的开箱即用解决方案),但或许你可以使用它。

此外,他的博客中有一些评论称在某些情况下会出现验证规则无法正确评估的问题,但这种情况从未在我的环境中出现过。


在WPF中,必须针对每个属性更改触发它。 - Shimmy Weitzhandler
这是一个有趣的完成方式 - 我可能会用一些这些想法来修改我的版本(上面的版本)。 - Jeremy Gruenwald

3

您可能会对 BookLibrary 示例应用程序感兴趣,它属于 WPF 应用程序框架 (WAF)。它正好符合您的要求:在 WPF 和 Entity Framework 中使用 DataAnnotations。


1

我有同样的问题,并找到了以下想法:


0

0
使用“伙伴类”。请参考这个教程中的第4点。

您提供的链接在WPF中不适用,我想我在我的帖子中提到了这一点。 - Shimmy Weitzhandler

0

你忘了我在谈论由EDM设计器生成的实体对象。 - Shimmy Weitzhandler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接