Caliburn.Micro实现了INotifyDataErrorInfo

时间:2014-05-21 08:01:24

标签: c# validation caliburn.micro

我正在尝试使用Caliburn.Micro MVVM框架找到一个优雅的解决方案来实现INotifiyDataErrorInfo

我想限制每个需要实现验证的VM中重复的代码量。 我开始编写一个继承Screen并实现INotifiyDataErrorInfo的类。它工作正常,一切正常,直到我需要在不是ScreenConductor的VM上进行验证。

当然,我可以创建一个继承Conductor并实现INotifyDataErrorInfo的类但这非常烦人,因为我基本上必须创建Caliburn.Micro所有“基类”的自己版本。

我的一个解决方案是保留Screen基类并创建一个{I}}接口,我将注入到我的VM中,如下所示:

IValidator

然后以这种方式在VM中使用它。

public interface IValidator<T> where T : INotifyDataErrorInfo
{
    void Validates(T instance);

    IEnumerable GetErrors(string propertyName);
    bool HasErrors { get; }

    void Validate();
    void ValidateProperty<TValue>(TValue value, string propertyName = null);
    void ValidateProperty<TValue, TProperty>(TValue value, Expression<Func<TProperty>> property);
}

这很好用,因为在VM中实现public class CreateCarViewModel : Conductor<CreateCarViewModel>.Collection.OneActive, INotifyDataErrorInfo { private readonly IValidator<CreateCarViewModel> validator; public CreateExperimentViewModel(IValidator<CreateCarViewModel> validator) { this.DisplayName = "Select a car"; this.validator = validator; this.validator.Validates(this); } [Required] public string CarName { get { return this.carName; } set { if (this.carName != value) { this.carName = value; this.validator.ValidateProperty(value, () => this.CarName); this.NotifyOfPropertyChange(() => CarName); } } } public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public System.Collections.IEnumerable GetErrors(string propertyName) { return this.validator.GetErrors(propertyName); } public bool HasErrors { get { return this.validator.HasErrors; } } ... } 非常简单,但我遇到的问题是触发INotifyDataErrorInfo事件。它必须由ErrorChanged的实现触发,因为他是知道错误何时发生变化的人,当然他不能直接触发。

我的一个想法是在IValidator中创建一个事件并在VM中订阅它以便它可以触发它自己的事件,但我发现它会产生很多代码。

有没有人有更好的主意?

由于

2 个答案:

答案 0 :(得分:1)

我为CM编写了一个小插件,以启用流畅的构建器式验证。也许它会帮助你。随意使用它:https://github.com/AIexandr/Caliburn.Micro.Validation 用法示例:

public class PaymentEditorViewModel() : ValidatingScreen
{
  public PaymentEditorViewModel()
  {
    AddValidationRule(() => PaymentSum).Condition(() => PaymentSum <= 0).Message("Please enter payment sum");
  }

  #region PaymentSum property
  decimal _PaymentSum;
  public decimal PaymentSum
  {
    get
    {
      return _PaymentSum;
    }
    set
    {
      _PaymentSum = value;
      NotifyOfPropertyChange(() => PaymentSum);
    }
  }
  #endregion
}

答案 1 :(得分:0)

如果你让IValidator公开与VM相同的事件,那么它的连线代码并不过分,例如:

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public void Validate()
    {
        if (ErrorsChanged != null)
            ErrorsChanged(instance, new DataErrorsChangedEventArgs("someProperty"));
    }

并在VM中:

 validator.ErrorsChanged += (sender, args) => ErrorsChanged(sender, args);

但我猜你已经回答了自己的问题而没有告诉我们;)