【问题标题】:Validation between multiple fields in different levels不同级别的多个字段之间的验证
【发布时间】:2011-12-06 09:19:10
【问题描述】:

我在多个字段之间进行验证时遇到问题。例如,我有一个名为 RangeDateViewModel 的 ViewModel,它包含一个名为 DateViewModel 的类的 2 个实例——它们分别代表开始日期和结束日期。

所以我的绑定看起来像这样:

<TextBox Text="{Binding StartDate.Date, ValidateOnDataError=True}">
<TextBox Text="{Binding EndDate.Date, ValidateOnDataError=True}">

我的RangeDateViewModel 类实现了IDataErrorInfo 接口。 在我的计划中,RangeDateViewModel 将通过在 IDataErrorInfo["propertyName"] 函数中应用如下验证逻辑来​​验证开始日期是否早于结束日期:

public string this[string columnName]
{
     get
     {
        return ValidationError();
     }
}

问题是它永远不会被调用,而是调用驻留在每个DateViewModel 类中的IDataErrorInfo 属性。

我猜这是因为绑定的属性不在RangeDateViewModel的同一级别,而是在子DateViewModel内部。

我认为我的需求非常基本,必须有一个简单的解决方案来解决这个问题。

我尝试使用 ValidationRules 而不是 IDataErrorInfo,但是我无法让 ViewModel 从 ValidationRules 获知当前的验证状态。

【问题讨论】:

    标签: wpf validation mvvm idataerrorinfo validationrules


    【解决方案1】:

    尝试使用以下方法:

    1. DateViewModel 创建一个DataTemplate

      <DataTemplate DataType="{x:Type ViewModels:DateViewModel}">
          <TextBox Text="{Binding Date}">
      </DataTemplate>
      
    2. 将此 ViewModel 的实例绑定到 ContentControl 并在该绑定上将 ValidateOnDataError 设置为 true

      <ContentControl Content="{Binding StartDate, ValidateOnDataError=True}" />
      <ContentControl Content="{Binding EndDate, ValidateOnDataError=True}" />
      
    3. RangeDateViewModel 中订阅StartDateEndDatePropertyChanged 事件,并在引发时使用StartDate / EndDate 引发PropertyChanged 事件:

      StartDate.PropertyChanged += (s, e) => InvokePropertyChanged("StartDate");
      EndDate.PropertyChanged += (s, e) => InvokePropertyChanged("EndDate");
      

    【讨论】:

    • 谢谢丹尼尔!我尝试了你的建议,但显然它仍然不够好。 IDataErrorInfo 属性确实正在被访问,但仅在模板初始化时才被访问,而不是在实际数据更改后。我猜这是因为 StartDate 和 EndDate 是复杂的对象,它们本身并没有被更改,而是它们内部的属性,这不足以使它们引发 PropertyChanged。当内部日期属性发生变化时,也许我应该以某种方式引发一个事件?
    • 再次感谢丹尼尔!尽管我仍然面临最后一个小问题,但这已经奏效了。使用此解决方案,结果是值无效时标记为红色的两个控件。我希望它们不是被标记为红色,而是包含这两个字段的 Stackpanel 将被标记为已读。最好不要标记这两个字段,但这不是必须的。我尝试在 RangeDateViewModel 上名为“HasErrors”的布尔属性上应用 DataTrigger,它将“Validation.HasError”设置为 true,但不幸的是,它是一个只读属性。我希望你也能帮助我解决这个问题。
    • @Dror:再上一步:为 RangeDateViewModel 而不是 DateViewModel 创建一个数据模板...相应地调整其他两点。
    • 谢谢丹尼尔!出于某种奇怪的原因,我想到了它,但实际上并没有认真考虑它。这个解决方案需要一些事件订阅和取消订阅,但我想这是迄今为止存在的最好的解决方案。非常感谢!
    【解决方案2】:

    我遇到的问题是 public string this[string columnName] 只是在前一周没有被调用。

    解决方案很简单。 绑定 WPF 绑定引擎无法遵循我的 ViewModel 的嵌套。

    我曾假设我需要在 ViewModel 中实现作为当前 DataContext 的属性,但相反它需要在 绑定到控件的 ViewModel 中实现强>。

    示例:

    <TextBox Text="{Binding Path=ProductViewModel.DescriptionViewModel.ProductName,
                                        Mode=TwoWay,
                                        ValidatesOnDataErrors=True,
                                        NotifyOnValidationError=True}" />
    

    这里DescriptionViewModel 是包含绑定属性的类。 IDataErrorInfo 需要在该类中实现(notProductViewModel 或可能包含它的层次结构中的另一个类)然后一切都会正常工作。

    【讨论】:

    • 您好老师,感谢您的评论。我知道 IDataErrorInfo 在绑定层次结构的较低类中实现时工作正常,但我遇到了 2 个问题。 1 - 我有两个类参与验证逻辑,但这些较低级别的类中的每一个都不认识彼此。 2 - 如果值无效,我不希望仅将其中一个字段标记为红色。我希望将整个控件标记为红色。
    猜你喜欢
    • 2021-03-24
    • 2018-04-29
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多