2017-02-27 54 views
1

想象一下DataGrid的一个DataGrid,它的ItemsSource设置为ObservableCollection。此集合为DataGrid中的每一行提供了查看模型。视图模型反过来提供一行中显示的数据和可能更改此数据的命令。此外,我在DataGridRowValidationRules属性中添加了一条规则。如果我输入无效数据,此验证规则正常工作。验证基础数据更改时的行

但是,如果通过视图模型提供的命令将无效数据更改为有效数据,则只有当DataGrid中的当前行失去焦点时,才会再次触发行验证规则。因此,显示的数据可能实际上是有效的,但DataGrid仍显示一个红色感叹号,表明它具有无效数据。在当前行失去焦点或我再次输入有效数据之前,情况依然如此。

如何强制对当前行进行第二次验证?我已经设置了ValidatesOnTargetUpdated="True"但这并没有解决问题。我也实现了INotifyPropertyChanged接口,但这也没有解决问题。

解决方案

随着用户mm8指出,INotifyDataErrorInfo是去的方法。我删除了行验证规则,并在我的视图模型中公开了名为HasErros的属性,该属性代理了我的模型的HasErrors属性,该属性依次执行INotifyDataErrorInfo。接下来,我添加了一个自定义的RowValidationErrorTemplate

<DataGrid.RowValidationErrorTemplate> 
    <ControlTemplate> 
     <Grid> 
      <Ellipse Width="12" Height="12" Fill="Red"/> 
      <Label Content="!" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" 
        Foreground="White" FontSize="11"/> 
     </Grid> 
    </ControlTemplate> 
</DataGrid.RowValidationErrorTemplate> 

,并创建以下的自定义样式DataGridRowHeader

<Style x:Key="MyDataGridRowHeaderStyle" TargetType="{x:Type DataGridRowHeader}"> 
    <!-- ... --> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type DataGridRowHeader}"> 
       <Border> 
        <Grid> 
         <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> 
         <Control SnapsToDevicePixels="True" 
           Template="{Binding ValidationErrorTemplate, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" 
           Visibility="{Binding Path=HasErrors, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}"/> 
        </Grid> 
       </Border> 
       <!-- ... --> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Visibility的结合。 HasErrors属性是我上面提到的代理属性。

最后,使用该样式在DataGrid如下

<DataGrid RowHeaderStyle="{StaticResource MyDataGridRowHeaderStyle}" 
... 

BoolToVisibilityConverter的实现可以发现here

回答

1

而不是添加ValidationRuleRowValidationRulesDataGrid哟的财产您可以在视图模型类中实现INotifyDataErrorInfo界面,并在需要刷新行/项目状态时提升其ErrorChanged事件。

这是实现数据验证的MVVM方式。使用ValidationRule不是。

WPF 4.5:验证数据在使用INotifyDataErrorInfo接口:https://social.technet.microsoft.com/wiki/contents/articles/19490.wpf-4-5-validating-data-in-using-the-inotifydataerrorinfo-interface.aspx

1

您可以处理CellEditEnding,找到行并调用BindingGroupUpdateSources

private void dataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) 
    { 
     DataGrid dg = sender as DataGrid; 
     foreach (var r in dg.Items) 
     { 
      DataGridRow row = dg.ItemContainerGenerator.ContainerFromItem(r) as DataGridRow; 
      if (row != null) 
       row.BindingGroup.UpdateSources(); 
     } 
    } 

同时,注意设置UpdateSourceTrigger=PropertyChanged您绑定了。

编辑

请注意,您还可以使用EventTrigger

<DataGrid x:Name="dataGrid1" ItemsSource="{Binding Models}" DataContext="{Binding}"> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="CellEditEnding" > 
      <i:InvokeCommandAction Command="{Binding PCommand}" 
            CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}}"> 
      </i:InvokeCommandAction> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</DataGrid> 

其中PCommand是在视图模型和:

private void DoPCommand(object parameter) 
    { 
     DataGrid dg = parameter as DataGrid; 
     if (dg != null) 
      foreach (var r in dg.Items) 
      { 
       DataGridRow row = dg.ItemContainerGenerator.ContainerFromItem(r) as DataGridRow; 
       if (row != null) 
        row.BindingGroup.UpdateSources(); 
      } 
    }