繁体   English   中英

Caliburn.Micro实现INotifyDataErrorInfo

[英]Caliburn.Micro implementing INotifyDataErrorInfo

我正在尝试找到一种优雅的解决方案,以利用Caliburn.Micro MVVM框架实现INotifiyDataErrorInfo

我想限制在每个需要实施验证的VM中重复的代码量。 我从编写一个继承Screen并实现INotifiyDataErrorInfo的类开始。 它可以正常工作,并且一切都很好,直到我需要在不是Screen而是Conductor的VM上进行验证为止。

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

我的一个解决方案是保留Screen基类,并创建一个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 ,因为在VM中实现INotifyDataErrorInfo非常简单,但是我遇到的问题是触发ErrorChanged事件。 它必须由IValidator的实现来触发,因为他是知道错误何时已更改的人,当然他不能直接触发。

我的一个想法是在IValidator有一个事件,然后在VM中订阅它,以便它可以触发自己的事件,但是我发现它无济于事地编写了很多代码。

有谁有更好的主意吗?

谢谢

我为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
}

如果您让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);

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM