Double clicking datagrid starts unwanted BeginEdit

Double clicking datagrid starts unwanted BeginEdit

Old forum URL: forums.lhotka.net/forums/t/11888.aspx


pegesaka posted on Sunday, March 17, 2013

I have a datagrid were users can add an item in a cell by selecting that cell and initiating the action by clicking a button next to the grid (easiest, first draft implementation). It essentially creates new items within the object graph, then opens a form so users can edit their properties. If the user cancels this form, I want the object graph to undo completely. This is the click event handler for the "Add" button.


    private void cbAddShift_Click(object sender, RoutedEventArgs e) {
      if (gdShifts.SelectedCells.Count == 1) {
        DataGridCellInfo oCell = gdShifts.SelectedCells[0];
        FoRJobs.BeginEdit();
        RosteredShift boNewShift = FoRJobs.RostersShifts.AddShiftForJob((RosteredJob)oCell.Item, oCell.Column.DisplayIndex);
        ShiftEdit oTester = new ShiftEdit((JobAssignment)(boNewShift.CurrAssignments[0]));
        if ((bool)oTester.ShowDialog())
          FoRJobs.ApplyEdit();
        else
          FoRJobs.CancelEdit();
        Refresh();
      }
    }

FoRJobs is the root of the object graph, ShiftEdit is the form used to edit this new item (shift).

This all works fine, but client wants same functionality if a cell in the grid is double clicked. So I have just got both the button click handler and grid double click handler to pass cell info to this common method


    private void AddShift(DataGridCellInfo oCellInfo) {
      FoRJobs.BeginEdit();
      RosteredShift boNewShift = FoRJobs.RostersShifts.AddShiftForJob((RosteredJob)oCellInfo.Item, oCellInfo.Column.DisplayIndex);
      ShiftEdit oTester = new ShiftEdit((JobAssignment)(boNewShift.CurrAssignments[0]));
      if ((bool)oTester.ShowDialog())
        FoRJobs.ApplyEdit();
      else
        FoRJobs.CancelEdit();
      Refresh();
    }

But the double click results in an "Edit level mismatch in CopyState" error.

The difference between the two actions is that a double click causes the grid to issue a BeginEdit on the row item first (this is a child object of a list, which itself is a child of the object graph root above), before running the handler. As a result of a BindingEdit? From the callstack, this -

PresentationFramework.dll!System.Windows.Data.ListCollectionView.EditItem(object item) + 0x7b bytes

calls this in BusinessBase.cs

void System.ComponentModel.IEditableObject.BeginEdit()

which raises the EditLevel of this child item individually, which then causes the error when the entire graph is put into edit via my code.

Is there a way that I can stop this unwanted BeginEdit on the child item? Am I missing something in the set up of the grid or business objects? Do I need to call a CancelEdit first in the double click handler?

Your assistance would be greatly appreciated,

Perry

pegesaka replied on Saturday, March 23, 2013

For those following that may come across this problem, the initial workaround I implemented was to call CancelEdit() on the EC which is the row item put into edit by the grid. This stopped the "Edit level mismatch" problem, allowed me to put the entire graph into edit, edit the objects and apply or cancel the edit.

However if you then need to refresh the grid's datacontext or itemssource you will get a "'Refresh' is not allowed during an AddNew or EditItem transaction" error, as it appears that the grid is still in edit mode. There are numerous ways to cancel the grid's editing state, some work, some dont, but the most effective way I found, is to use IEditableCollectionView as below -

        IEditableCollectionView oColl = (IEditableCollectionView)gdShifts.Items;
        if (oColl.CanCancelEdit)
          oColl.CancelEdit();

The help on the net suggests issing this just before you refresh the datacontext (I spose because you obviously dont want to still be editing at this point), which works fine. But I found that issing the above code in the double click handler immediately cancels the EC edit as well, putting the grid and my CSLA objects in a consistent state before I implement my own editing.

My question is, if a double click puts the grid into edit mode, which then puts the row item object into edit mode via IEditableObject, is it then up to the grid to then either issue an accept or cancel, passing it on to the EC? My problem is that I need more than just a datagrids row item to be in edit mode, I need the entire object graph.

Cheers,

Perry

Copyright (c) Marimer LLC