2017-02-27 51 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(); 
      } 
    }