WPF DataGrid 'Refresh' is not allowed during an AddNew or EditItem transaction mvvm
Asked Answered
R

4

15

I have the following grid

    <DataGrid

        x:Name="TablesDataGrid"
        Grid.Column="0"
        Grid.Row="1"
        ItemsSource="{Binding FilteredModels.View}"
        AlternationCount="2"
        AutoGenerateColumns="False"
        CanUserSortColumns="True"
        CanUserReorderColumns="False"
  CanUserDeleteRows="False"
  CanUserAddRows="False"
  SelectionMode="Extended"
        IsReadOnly="False"
  SelectionUnit="FullRow"
        RowHeight="25"
  HorizontalAlignment="Stretch"
  ColumnWidth="Auto">
            <DataGrid.Columns >
                <DataGridCheckBoxColumn Width="*" Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"  IsReadOnly="False">
                    <DataGridCheckBoxColumn.HeaderTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CheckAll}"/>
                        </DataTemplate>
                    </DataGridCheckBoxColumn.HeaderTemplate>
                </DataGridCheckBoxColumn>
                <DataGridTextColumn Header="Source Table" Binding="{Binding SourceTableFullName}" Width="4*"></DataGridTextColumn>
                <DataGridTextColumn Header="EDW Schema"  Binding="{Binding SchemaName}" Width="2*"></DataGridTextColumn>
                <DataGridTextColumn Header="EDW Table" Binding="{Binding TableName}" Width="4*"></DataGridTextColumn>
                <DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="*"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

and then i have a seachCommand with performs the search on the collectionViewSource FilteredModels in the viewmodel and then calls

this.FilteredModels.View.Refresh();

when a user checks a few of the checkboxes and sends the grid into editmode and then performs a search we get the following error

WPF DataGrid 'Refresh' is not allowed during an AddNew or EditItem transaction

is there a way to force the grid out of edit mode when a check box is checked or maybe even when the seach button is clicked or some other fix for this?

thanks!

Rosebud answered 25/11, 2013 at 22:22 Comment(0)
M
50

I know its too late to answer...but for someone who is looking for answer

use cancelEdit or commitEdit method two times in a sequence like this

//for commit

this.datagrid_layers.CommitEdit();
this.datagrid_layers.CommitEdit();

//for cancel

this.datagrid_layers.CancelEdit();
this.datagrid_layers.CancelEdit();
Mariellamarielle answered 15/2, 2015 at 13:26 Comment(5)
I don't know why using it only once doesn't work, but two times in a sequence works?? any idea...Lepanto
It is never too late :D. Your answer saves me a lot of time !!! @Ash: My guess is the datagrid stores two transactions. One for the column and another for the row. You need to commit both before refreshing the collection view.Vitkun
For me it's the same, two calls work, one is not enough. Also thanks for the "late" answer, wasn't too late for me too.Lazarolazaruk
Probably this is the reason: "If a cell is currently in edit mode, the CancelEdit method cancels the cell edit, but not any pending row edits. If a cell is not in edit mode, CancelEdit cancels all pending row edits." CancelEdit on msdnDiller
Instead of calling CommitEdit twice (which is confusing), call: CommitEdit(DataGridEditingUnit.Row, true);Sanhedrin
S
6

There is a clean MVVM solution to the problem. First off, your ViewModels must implement IEditableObject interface (no-op should be enough). That, however, is not enough since the DataGrid will not listen to IEditableObject.CancelEdit.
Another problem is, that neither ICollectionView nor IEditableCollectionView implement the other one. While only ICollectionView can refresh, only IEditableCollectionView can commit/cancel. Luckily collection view returned by CollectionViewSource.GetDefaultView implements both:

// ViewModel.cs
public class ItemVM : IEditableObject, INotifyPropertyChanged { }

public class ModuleVM : INotifyPropertyChanged {
   ICollectionView Items { get; }

   public ModuleVM(ObservableCollection<ItemVM> items) {
      Items = CollectionViewSource.GetDefaultView(items);
   }

   public void RefreshSafely() {
      ((IEditableCollectionView)Items).CancelEdit(); // alterantively, CommitEdit()
      Items.Refresh();
   }
}

Or in other words, you can cast ICollectionView to IEditableCollectionView and call CancelEdit() first.

Skew answered 8/11, 2019 at 15:22 Comment(1)
Thank You. I spent many hours yesterday struggling with this. Every time i changed a checkbox on a datagrid and then tried to open a Dialog, i got the DeferRefresh exception. I'm using MVVM so i couldn't just commitEdit on the datagrid. By combining your example above as follows: var Items = CollectionViewSource.GetDefaultView(vm.ThisCustomer.CurrentOrder.OrderDetailsList); ((System.ComponentModel.IEditableCollectionView)Items).CommitEdit(); Items.Refresh(); The issue was resolved. Nice!!Weatherbound
Q
5

you should be able to cast the selected item to IEditableObject and call EndEdit on it, or call the grids CancelEdit method.

Quarters answered 25/11, 2013 at 23:52 Comment(0)
P
0

Here is my solution, adapt it to your need.

private void CommitEditRefreshViewSafely()
{
    ((IEditableCollectionView)MyCollectionViewList.View).CommitEdit();
    MyCollectionViewList.View.Refresh();
}
Popovich answered 8/2 at 22:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.