EntityFramework and DataAnnotations, errors not showing
I am using the entity framework and trying to use Data Annotations for validation. I have looked up several examples on google and found the same structure everywhere. I followed it, but for some reason my errors aren't showing up in the form. I know, I might have to validate the properties manually with the Validator
class, but I cannot figure out where to do it. I know I can listen to the PropertyChanging
event, but that only passes the name of the property, and not the value that is about to be assigned. Anyone have any ideas how I can get around this?
Thanks in advance.
[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; }
}
}
the 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, UpdateSour开发者_开发知识库ceTrigger=PropertyChanged, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
Edit: (implemented the IDataErrorInfo class based on Rachel's comment)
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); }
}
the xaml
<fx:TextBox Width="250" Height="20" CornerRadius="5" BorderThickness="0" MaxLength="50" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
I've succesfully implemented similar scenario and I strongly suggest you to look at how it has been implemented in http://waf.codeplex.com/. It uses Data Annotations validation with Entity Framework and WPF.
One significant issue you might have with making this work with Entity Framework is that Data Annotations Validator will ignore your metadata until you Add metadata for EntityObject somewhere in your code before validating:
TypeDescriptor.AddProviderTransparent(new
AssociatedMetadataTypeTypeDescriptionProvider(typeof(EntityObject)),
typeof(EntityObject));
Additional information: .NET 4 RTM MetadataType attribute ignored when using Validator
Also, I think that your metadata should be public and not sealed.
Here is an excerpt from DataErrorInfoSupport.cs, for quick reference:
/// <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();
}
}
精彩评论