我遇到了一个棘手的问题,即 WPF 数据网格和验证错误工具提示在验证消息更改时未更新。这是 .Net 4 代码,所以我不能使用INotifyDataErrorInfo。
我有一个绑定到数据网格的ObservableCollection 。集合中的对象类型实现了IDataErrorInfo以便我们可以支持验证并突出显示具有无效值的字段。这在大多数情况下都可以正常工作。但是,在以下情况下,工具提示中显示的消息存在问题:
- 字段 A 有两条规则 Rule 1 和 Rule S(共享规则)
- 字段 B 有一个规则 Rule S(共享规则)
- 规则 S 是共享规则,而不是同时引用字段 A 和字段 B
如果规则 1 和规则 S 都无效,我们会为每个字段显示以下验证工具提示,这是我们想要的行为:
Field A < "Rule 1 is invalid. Rule S is invalid" Field B < "Rule S is invalid"
如果我们现在编辑字段 B 以使规则 S 有效。我们希望两个工具提示消息都更新如下:
Field A < "Rule 1 is invalid." Field B < (valid - no tooltip)
注意,字段 A 的验证状态没有改变(Validation.HasError 没有改变值),只有工具提示绑定的消息。
我们实际看到的是:
Field A < "Rule 1 is invalid. Rule S is invalid"
Field B < (valid - no tooltip)
注意此时类实例上的基础 ValidationError 数据是正确的。
UI 似乎不会更新字段 A 的工具提示文本,除非我们强制它重新查询状态并再次调用 IDataErrorInfo.this[string columnName]。我发现强制这种情况发生的唯一方法是手动引发字段 A 的属性更改事件。但是,我不想这样做,因为字段 A 的值实际上并没有改变,只有边界错误信息。虽然此解决方案有效,但额外和不必要的属性更改事件会影响大量数据的性能。
我可以做些什么来强制为字段 B 调用 IDataErrorInfo.this[string columnName] 而不必引发属性更改事件?
注意这里是我们用来显示验证消息的错误数据模板。
<!-- ERROR HANDLING Data Template -->
<Style x:Key="controlBaseStyle"
TargetType="{x:Type Control}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Red"
BorderThickness="2"
Visibility="{Binding ElementName=placeholder, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<AdornedElementPlaceholder x:Name="placeholder"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ToolTipService.ShowOnDisabled" Value="true"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem, Converter={StaticResource ErrorContentConverter}}"/>
</Trigger>
<!--We don't want to see the validation if the control is disabled. This doesn't affect it if the control is read only. -->
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<AdornedElementPlaceholder x:Name="placeholder"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>