C# 使用Catel将验证从模型传播到视图

C# 使用Catel将验证从模型传播到视图,c#,wpf,mvvm,catel,C#,Wpf,Mvvm,Catel,我正在开发一个使用Catel的MVVM(4.0.0)实现的程序。我有一个模型类,作为一些业务逻辑,它必须遵守关于它的属性值之一的规则 例如,假设我有一个Trap类,它有一个TargetValue和一个CurrentValue属性。对于此类,有一条规则必须强制执行TargetValue属性只能小于或等于(您不应该在setter中验证,因为setter负责设置对象的值。假设模型使用INotifyPropertyChanged和IDataErrorInfo(或INotifyDataErrorInfo)

我正在开发一个使用Catel的MVVM(4.0.0)实现的程序。我有一个模型类,作为一些业务逻辑,它必须遵守关于它的属性值之一的规则


例如,假设我有一个
Trap
类,它有一个
TargetValue
和一个
CurrentValue
属性。对于此类,有一条规则必须强制执行
TargetValue
属性只能小于或等于(您不应该在setter中验证,因为setter负责设置对象的值。假设模型使用INotifyPropertyChanged和IDataErrorInfo(或INotifyDataErrorInfo),你可以用卡特尔做大事

例如,在ModelBase中,您可以覆盖ValidateFields或ValidateBusiness规则,甚至可以对您的模型应用自定义验证器。然后ModelBase将自动为您实现更改通知和验证接口

接下来,VM包含陷阱,例如下面的VM(请注意,此示例使用Catel.Fody):


在本例中,您将
Trap
属性定义为model。这意味着Catel将监视它以获取通知,并将视图模型上的属性映射到模型,反之亦然。现在有一件很酷的事情:它不仅映射属性值,还映射验证规则。这意味着该视图模型就足够了您不应该在setter中进行验证,因为setter负责设置对象的值。假设模型使用INotifyPropertyChanged和IDataErrorInfo(或INotifyDataErrorInfo),您可以使用Catel做大事

例如,在ModelBase中,您可以覆盖ValidateFields或ValidateBusiness规则,甚至可以对您的模型应用自定义验证器。然后ModelBase将自动为您实现更改通知和验证接口

接下来,VM包含陷阱,例如下面的VM(请注意,此示例使用Catel.Fody):


在本例中,您将
Trap
属性定义为model。这意味着Catel将监视它以获取通知,并将视图模型上的属性映射到模型,反之亦然。现在有一件很酷的事情:它不仅映射属性值,还映射验证规则。这意味着该视图模型就足够了您可以在模型中实施验证。

在讨论了Catel的功能后,由于操作顺序的原因,似乎通过“常规”验证流程无法实现此目的:

  • 属性设置器
  • 验证字段
  • 错误信息已准备好用于虚拟机
解决方案如下:

  • CurrentValue
    属性设置器应该是私有的,这样它就不能被绑定到(直接绑定或使用装饰等通过VM绑定)
  • 添加到
    Trap
    IDataErrorInfo
    (或
    INotifyDataErrorInfo
    )实现中
  • 实现一个
    SetCurrentValue
    函数,该函数验证数据并仅在合法的情况下进行设置。如果不合法,则调用
    IDataErrorInfo
    机制
  • 在UI中-绑定到函数而不是属性(例如)

此方法应满足上述要求-属性值在任何用例中都不会无效,但仍然可以与UI协调。

在讨论了Catel的功能后,由于操作顺序的原因,通过“常规”验证流程似乎无法达到目的:

  • 属性设置器
  • 验证字段
  • 错误信息已准备好用于虚拟机
解决方案如下:

  • CurrentValue
    属性设置器应该是私有的,这样它就不能被绑定到(直接绑定或使用装饰等通过VM绑定)
  • 添加到
    Trap
    IDataErrorInfo
    (或
    INotifyDataErrorInfo
    )实现中
  • 实现一个
    SetCurrentValue
    函数,该函数验证数据并仅在合法的情况下进行设置。如果不合法,则调用
    IDataErrorInfo
    机制
  • 在UI中-绑定到函数而不是属性(例如)

此方法应满足上述要求-属性值在任何用例中都不会无效,但仍然可以与UI协调。

我使用
observeObject
作为模型类的基础,以保持简单。据我所见,此类不支持require机制。我可能会更改它(虽然由于“开销”我不太愿意,但我认为(如果我错了,请纠正我)验证可能会标记错误,但基础值仍将更改-或者它是否完全“取消”更新?如果它不取消,此解决方案将不适用于我,因为其他线程我的“监视”此(陷阱)对象,并可能使用非法值。您仍然可以使用ObserveObject,但如果需要验证,您a)需要自己编写,或者b)使用经过多年优化的Catel。这取决于您。我毫不怀疑Catel的代码比我编写的任何代码都好。我关心的是事件的实际顺序-使用内部验证是否可以解决我的问题-如果存在验证错误-它是否会阻止实际更新属性?假设我使用ValidateFields-我在函数中检查条件的属性值,我可以发出错误/警告-但由于违反了条件,时间已经太晚了…或者我缺少了什么?您只能验证(并保持验证状态)如果该属性确实可以设置。那么您可以设置该属性,但是模型将无效(这是正常行为)。谢谢
public class MyTrapViewModel : ViewModelBase
{
    public MyTrapViewModel(Trap trap)
    {
        Argument.IsNotNull(() => trap);

        Trap = trap;
    }

    [Model]
    [Expose("CurrentValue")]
    [Expose("TargetValue")]
    private Trap Trap { get; set; }
}