19

我有兴趣使用 WinForms 应用程序和 Entity Framework 5 设置客户端验证。我知道我可以实现 IValidatableObject 接口来执行每个实体可能需要的自定义验证。

但是,由于我使用的是 WinForms,因此我想在用户填写表单时出现验证错误时使用 ErrorProvider 向用户显示一个很好的通知。是否可以使用 IValidatableObject 接口来实现此功能,或者我是否需要在我的实体上实现 IDataErrorInfo 接口才能使 ErrorProvider 正常工作?

如果您对更好的替代方案有任何其他建议,请告诉我,我也很乐意对此进行调查。

4

2 回答 2

10

假设您有一个名为的实体Car,并且此类包含一个需要验证的属性。

public class Car
{
  [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public int Id { get; set; }

  // Accepted values have to be between 1 and 5.
  public int NeedToBeValidatedRange { get; set; }
}

在我将称为实体的示例中,您必须为所有实体创建一个基类。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;

/// This is the base class for all entities and it provide a change notfication.
public abstract class Entity : INotifyPropertyChanged
{
  // Event fired when the property is changed!
  public event PropertyChangedEventHandler PropertyChanged;


  /// Called when int property in the inherited class is changed for ther others properties like (double, long, or other entities etc,) You have to do it.
  protected void HandlePropertyChange(ref int value, int newValue, string propertyName)
  {
    if (value != newValue)
    {
      value = newValue;
      this.Validate(propertyName);
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  /// Validate the property 
  /// <returns>
  /// The list of validation errors
  /// </returns>
  private ICollection<ValidationResult> PropertyValidator(string propertyName)
  {
    var validationResults = new Collection<ValidationResult>();
    PropertyDescriptor property = TypeDescriptor.GetProperties(this)[propertyName];

    Validator.TryValidateProperty(
      property.GetValue(this),
      new ValidationContext(this, null, null) { MemberName = propertyName },
      validationResults);

    return validationResults;
  }

  /// Validates the given property and return all found validation errors.
  private void Validate(string propName)
  {
    var validationResults = this.PropertyValidator(propName);
    if (validationResults.Count > 0)
    {
      var validationExceptions = validationResults.Select(validationResult => new ValidationException(validationResult.ErrorMessage));
      var aggregateException = new AggregateException(validationExceptions);
      throw aggregateException;
    }
  }
}

现在你应该修改 Car 类,它应该是这样的:

public class Car : Entity
{
  private int id;
  private int needToBeValidatedRange;

  [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public int Id
  {
    get
    {
      return this.id;
    }
    set
    {
      this.HandlePropertyChange(ref this.id, value, "Id");
    }
  }

  [Range(1, 5)]
  public int NeedToBeValidatedRange
  {
    get
    {
      return this.needToBeValidatedRange;
    }
    set
    {
      this.HandlePropertyChange(ref this.needToBeValidatedRange, value, "NeedToBeValidatedRange ");
    }
  }
}

在用户界面的某个地方,您正在创建汽车实体:

Car car1 = new Car();
car1.NeedToBeValidatedRange = 3;  // This will work!

Car car2 = new Car();
car2.NeedToBeValidatedRange = 6;  // This will throw ValidationException
  • WPF 支持非常好的ValidationException。
  • Winforms 部分支持 ValidationException 但现在您可以自由地处理它了。
于 2013-12-04T16:56:21.617 回答
5

有两种选择:

  • 使用 IValidateObject 和 IdataErrorInfo 扩展您的 poco 类,并在验证方法中引发 ui 错误。
  • 在调用 save changes 时捕获验证错误,并根据哪个实体字段生成验证错误直接调用 ErrorProvider。

有关使用 IValidateObject 扩展 poco 类并在调用保存更改时处理验证错误的示例,请参见以下内容。

http://msdn.microsoft.com/en-us/data/gg193959.aspx

于 2013-12-01T21:44:08.647 回答