我正在使用实体框架并尝试使用Data Annotations进行验证。我在google上查了几个例子,到处都找到了相同的结构。我跟着它,但由于某种原因,我的错误没有出现在表单中。我知道,我可能必须使用Validator
类手动验证属性,但我无法弄清楚在哪里做。我知道我可以听PropertyChanging
事件,但只传递属性的名称,而不是要分配的值。任何人都有任何想法如何解决这个问题?
提前致谢。
[MetadataType(typeof(Employee.MetaData))]
public partial class Employee
{
private sealed class MetaData
{
[Required(ErrorMessage = "A name must be defined for the employee.")]
[StringLength(50, ErrorMessage="The name must be less than 50 characters long.")]
public string Name { get; set; }
[Required(ErrorMessage="A username must be defined for the employee.")]
[StringLength(20, MinimumLength=3, ErrorMessage="The username must be between 3-20 characters long.")]
public string Username { get; set; }
[Required(ErrorMessage = "A password must be defined for the employee.")]
[StringLength(20, MinimumLength = 3, ErrorMessage = "The password must be between 3-20 characters long.")]
public string Password { get; set; }
}
}
xaml
<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="50" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="20" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
<fx:PasswordBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="20" Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
编辑:(根据Rachel的评论实现了IDataErrorInfo类)
public static class EntityHelper
{
public static string ValidateProperty(object instance, string propertyName)
{
PropertyInfo property = instance.GetType().GetProperty(propertyName);
object value = property.GetValue(instance, null);
List<string> errors = (from v in property.GetCustomAttributes(true).OfType<ValidationAttribute>() where !v.IsValid(value) select v.ErrorMessage).ToList();
return (errors.Count > 0) ? String.Join("\r\n", errors) : null;
}
}
[MetadataType(typeof(Employee.MetaData))]
public partial class Employee:IDataErrorInfo
{
private sealed class MetaData
{
[Required(ErrorMessage = "A name must be defined for the employee.")]
[StringLength(50, ErrorMessage="The name must be less than 50 characters long.")]
public string Name { get; set; }
[Required(ErrorMessage="A username must be defined for the employee.")]
[StringLength(20, MinimumLength=3, ErrorMessage="The username must be between 3-20 characters long.")]
public string Username { get; set; }
[Required(ErrorMessage = "A password must be defined for the employee.")]
[StringLength(20, MinimumLength = 3, ErrorMessage = "The password must be between 3-20 characters long.")]
public string Password { get; set; }
}
public string Error { get { return String.Empty; } }
public string this[string property]
{
get { return EntityHelper.ValidateProperty(this, property); }
}
xaml
<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="50" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
答案 0 :(得分:0)
我已经成功实施了类似的方案,我强烈建议您查看它是如何在http://waf.codeplex.com/中实施的。它使用Entity Framework和WPF进行数据注释验证。
使用Entity Framework进行此操作时可能遇到的一个重要问题是,在验证之前,在代码中的某处为EntityObject添加元数据之前,Data Annotations Validator将忽略您的元数据:
TypeDescriptor.AddProviderTransparent(new
AssociatedMetadataTypeTypeDescriptionProvider(typeof(EntityObject)),
typeof(EntityObject));
其他信息: .NET 4 RTM MetadataType attribute ignored when using Validator
此外,我认为您的元数据应该是公开的而不是密封的。
以下是DataErrorInfoSupport.cs的摘录,供快速参考:
/// <summary>
/// Gets an error message indicating what is wrong with this object.
/// </summary>
/// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
public string Error { get { return this[""]; } }
/// <summary>
/// Gets the error message for the property with the given name.
/// </summary>
/// <param name="memberName">The name of the property whose error message to get.</param>
/// <returns>The error message for the property. The default is an empty string ("").</returns>
public string this[string memberName]
{
get
{
List<ValidationResult> validationResults = new List<ValidationResult>();
if (string.IsNullOrEmpty(memberName))
{
Validator.TryValidateObject(instance, new ValidationContext(instance, null, null), validationResults, true);
}
else
{
PropertyDescriptor property = TypeDescriptor.GetProperties(instance)[memberName];
if (property == null)
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
"The specified member {0} was not found on the instance {1}", memberName, instance.GetType()));
}
Validator.TryValidateProperty(property.GetValue(instance),
new ValidationContext(instance, null, null) { MemberName = memberName }, validationResults);
}
StringBuilder errorBuilder = new StringBuilder();
foreach (ValidationResult validationResult in validationResults)
{
errorBuilder.AppendInNewLine(validationResult.ErrorMessage);
}
return errorBuilder.ToString();
}
}