简体   繁体   中英

WPF - Removal of DataGridRow with Validation.Error blocks DataGrid

This is a tricky one to explain:

I have a DataGrid and an (Xceed library) IntegerUpDown . The value of the IntegerUpDown defines the number of items in the DataGrid.ItemsSource and, therefore, the number of rows in the DataGrid .

The DataGrid.ItemsSource is an ObservableCollection(NPoint) , where NPoint has properties X and Y (both are doubles ). This means that if the user inserts a non-numeric value in the DataGrid , it fails validation and the standard ValidationError template with the red box and exclamation mark appears. Also, the DataGrid does not allow for further changes to its contents until this error is corrected.

All of this works just fine. However, I just had an idea and did an experiment. What if the user deletes the contents of a cell of the last row (which would apply a value of null ), causing a ValidationError and then changes the IntegerUpDown value so as to remove that invalid row? Does that free up the DataGrid , permitting the user to edit other cells or does the DataGrid continue blocked up?

So I did just that and the DataGrid continues frozen. The user can move to other cells, but cannot edit them. Even if the IntegerUpDown is altered once more to replace the deleted row, the DataGrid does not allow edits.

Here's a simple storybook of what I mean (click for larger image): 故事书 1. The initial state of the window 2. The user deletes the contents of the last row, triggering a ValidationError 3. The user reduces the "# Sections", removing the last row which was the cause of the ValidationError 4. The remaining cells of the DataGrid still cannot be edited. 5. After increasing the "# Sections", returning the removed row (now with the new value of 0, which is the default value for new rows), the other cells (including the new row) still cannot be edited.

Here's the relevant code. The special style given to the rows is because, depending on other parts of the window, the column (or just some of the rows) might be readonly. The binding of the DataGrid.ItemsSource is done in code-behind because, depending on the state of other parts of the window, the source differs. You'll also notice that though two columns appear, the DataGrid code below only contains one column. That's because it is actually two different DataGrids , one next to the other, each with one column, since the .ItemsSource for each column is different.

XAML

<Grid.Resources>
    <Style x:Key="ReadOnlyCheckX" TargetType="{x:Type DataGridRow}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsXReadOnly}" Value="True">
                <Setter Property="Tag" Value="ReadOnly" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Grid.Resources>
<!--...-->
<xctk:IntegerUpDown Name="nSections"
                    Minimum="3" Value="11"
                    ValueChanged="nSectionsChanged"/>
<!--...-->
<DataGrid x:Name="CoordinatesX"
          RowStyle="{StaticResource ReadOnlyCheckX}"
          AutoGenerateColumns="False"
          BeginningEdit="Coordinates_BeginningEdit">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="XColumn" Width="50"/>
    </DataGrid.Columns>
</DataGrid>

Code-behind

private void Coordinates_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
    if ((e.Row).Tag != null && (e.Row).Tag as string == "ReadOnly")
        e.Cancel = true;
}
private void nSectionsChanged(object sender, RoutedEventArgs e)
{
    var cable = DataContext as Cable;
    var o = sender as IntegerUpDown;
    int v = (int)o.Value;
    if (v > cable.Points.Count)
    {
        for (int i = cable.Points.Count; i < v; i++)
            cable.Points.Add(new Point());
    }
    else if (v < cable.Points.Count)
    {
        for (int i = v; i < cable.Points.Count; )
            cable.Points.RemoveAt(v);
    }
}

So, how can this be resolved? I think that since Validation only occurs on edits, it is not noticing that the guilty edit no longer exists (since it was removed, not edited away) and is therefore blocking any further edits. Is there a way of asking for a "please revalidate all this data?"

After some more searching, I found this solution . There are actually some other places asking the same thing, but when I asked the question I hadn't used the essential search term, which is the DataGrid 's HasCellValidationError property (which doesn't appear in the MSDN documentation). I'm posting this here just for future reference for others.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM