Windows forms and n-level undo problems

Windows forms and n-level undo problems

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


j0552 posted on Wednesday, November 07, 2012


Hi

I'm trying to update an old windows forms project with business objects databinding and n-level undo. I have a main form with a button to open a modal dialog. In the constructor of the dialog I get a child object from the parent and call BeginEdit before binding to a BindingSource.

If the user hits ok after editing I ApplyEdit before the dialog closes. I have been motitoring the editlevel:

           Debug.WriteLine(((IUndoableObject)_rule).EditLevel);

It is '1' when the form closes. But when I try to remove the child from it's collection in a DataGridView in the main form I get an error:

UndoException: Edit level mismatch in AcceptChanges

If I try to unbind the object, using the project tracker UnbindBindingSource method, I get a first chance 'Csla.Core.UndoException', the edit level changes to '0' but I can them remove the item from the datagridview on the main form.

I've tried to read up about n-level undo in the  Using CSLA 4 book but there is almost nothing about it. And I can't find my CSLA C# 2008 book!

Can you point me in the right direction? Is it worth me buying the 2008 book from amazon again?

Any help you can give me is appreciated.
Thanks
Andrew

JonnyBee replied on Wednesday, November 07, 2012

Some basic guidelines for Windows Forms:

Bind2UI:

  1. Always DataBind DropDown lists first
  2. Then databind data objects - start from "root" or "top -most" object and god down in object-structure

Unbind:

  1. Unbind in opposite sequence from 2) above.

Additional rules:

a) When objects are databound - Windows Forms databinding will assume it has total control of
BeginEdit/EndEdit/CancelEdit and you should NEVER call any of these methods on a databound object.

The reason can be found here in MSDN:
http://msdn.microsoft.com/en-us/library/system.componentmodel.ieditableobject.beginedit.aspx
"If BeginEdit is called on an object that is already being edited, the second and subsequent calls are ignored."
(JB) IE: The next EndEdit/CancelEdit/ApplyEdit will act on the first BeginEdit that was called from DataBinding)

CSLA follows the above requirement from MSDN documentation when BeginEdit is called by DataBinding
(through the IEditableObject.BeginEdit method) and thus follows - NEVER CALL any of these methods manually
when an object is databound . DataBinding will call these methods for EACH time the user enters/leaves a field
or row and assumes total ownership.

You may also read my blogpost for more details:
http://jonnybekkum.wordpress.com/2009/10/20/forms-databinding-the-magic-sequence-of-binduiunbindui/

Hope this helps.

j0552 replied on Thursday, November 08, 2012

Thanks for the guidelines and BindingHelper class. I am still having problems when I call ApplyEdit on my child object after unbinding the datasource.

 'Edit level mismatch in AcceptChanges'

The object exists in the following graph:

 BusinessBase, BusinessBindingListBase, BusinessBase

Is it because I am working on a child object? I also made sure the child list is unbound from it's binding datasource in the parent form.

I wondered if I should create a separate BO to edit instead of editing the child in the dialog window, although it suits my use case as it is.

All I'm trying to achieve is editing a form bound to the child object. If the OK button is clicked the changes are applied. If the form is canceled the obect is reverted to the previous state before the BeginEdit.

I'm running out of things I can try now.

JonnyBee replied on Thursday, November 08, 2012

Start by checking the EditLevel in the entire object structure before you open the child form and again before you call ApplyEdit.  

You should make sure to UnBind the entire object structure -  not the child list only.

If this doesn´t help - create a sample project and post as attachment here. This will make it much easier to help us pinpoint the correct solution..

j0552 replied on Friday, November 09, 2012

I managed to find out why I was getting the error. I needed to do an EndEdit on the BindingSource used by the DataGridView in the main form. I have tested it and things seem to behave as expected.

I am unsure about the requirement to unbind the whole object graph before using the n-level stuff in the BO. In my example I have the main form then a modal dialog, which also has another modal dialog. If I have to unbind the whole graph I would need to pass the main form binding source into each of the modal dialogs constructors and when I unbind, the rows in the datagrid will disappear untill I rebind.

Is this really what you mean by unbinding the whole structure?

JonnyBee replied on Saturday, November 10, 2012

In general terms - yes I prefer to have the entire object structure unboud. Some third party grid controls will assume total ownership of the structure and call BeginEdit all child and grandchild objects too.

If you stick with standard windows controls - then yes your solution is good and you may also look into Suspend/Resume binding. .

I would however not allow the Modal Dialogs to have knowlegde og and N-level undo - their responsibility should only be the objects involved and bind/unbind databinding safely.

Copyright (c) Marimer LLC