嗯,问题是大声说出来,答案就来了,所以,为了这个问题,我正在描述我所犯的错误和误解,以及如何通过将所有东西放在适当的位置来最终实现我的目标方式同时:
-
第一个错误:在数据网格中使用 BindingGroup 而不是 ItemBindingGroup。这允许您使用 NotifyOnValidationError 属性,因此 Validation.Error 事件正常触发。然后您可以忘记 DataGrid.RowValidationRules,因为您应该将验证规则放在 ItemBindingGroup 的 BindingGroup 对象中。
-
而 Validation.Error 处理程序可以在 Datagrid 中定义,而 Validation.ValidationAdornerSite 应该在 BindingGroup 对象中定义。
-
不要在 BindingGroup 的任何绑定中使用 UpdateSourceTrigger 属性。这是我做的一个误会,它会引发 不稳定 行为,因为 BindingGroup 会忽略这些绑定,而 Binding 会自行更新源代码。
这是我用来以正确方式将所有东西放在一起的代码:
定义 Datagrid 和 ItemBindigGroup
<DataGrid ItemsSource="{Binding Source={StaticResource WinViewSource}}"
Validation.Error="BindingGroup_Error" >
<DataGrid.ItemBindingGroup>
<BindingGroup NotifyOnValidationError="True" ValidatesOnNotifyDataError="True" Validation.ValidationAdornerSite="{Binding ElementName=ErrorListBox}" >
<BindingGroup.ValidationRules>
<YourValidationRule ValidationStep="UpdatedValue" ValidatesOnTargetUpdated="False"/>
</BindingGroup.ValidationRules>
</BindingGroup>
</DataGrid.ItemBindingGroup>
<...>
</DataGrid>
<ListBox Name="ErrorListBox" Style="{StaticResource ListBoxErrorStyle}" Button.Click="GoToErrorButton_Click"/>
ValidationAdornerSite 的 ListBox 的样式。
<Style x:Key="ListBoxErrorStyle" TargetType="{x:Type ListBox}" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="ItemsSource" Value="{Binding (Validation.ValidationAdornerSiteFor).(Validation.Errors), RelativeSource={RelativeSource Self}}" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid Background="LightYellow">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Go to" Visibility="{Binding ErrorContent.ButtonGoToVisibility}" />
<TextBlock Grid.Column="1" Text="{Binding Path=ErrorContent.ErrorCode}" Margin="3"/>
<TextBlock Grid.Column="2" Text="{Binding Path=ErrorContent.ErrorMessage}" Margin="3"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
将 ItemsSource 绑定到 Validation.Errors 是不够的,因为尽管任何时候出现验证错误,ListBox 都会检查最后一个 ListViewItem 是否有 Validation.Errors,这将是 last ListViewItem 而不是 当前 ListViewItem。为避免这种情况,您需要 Validation.Error 事件才能重新附加:
Private Sub BindingGroup_Error(sender As Object, e As ValidationErrorEventArgs)
Validation.SetValidationAdornerSite(DirectCast(e.OriginalSource, DependencyObject), ErrorListBox)
End Sub
我的客户要求包括一个非常简单的对象,即带有 3 个属性的 ErrorContent,这些值应该在验证规则中定义,以便找到错误的原因:
Public Class ErrorContent
Public Property ErrorCode As String
Public Property ErrorMessage As String
Public Property ButtonGoToVisibility As Visibility = Visibility.Visible
End Class
通过上述操作,您将在屏幕上任何您想要的列表中看到所有验证错误,并且用户可以获得更好的处理它们的体验。