DataGridView Child not Saved on Form Close

DataGridView Child not Saved on Form Close

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


FatPigeon posted on Friday, January 11, 2008

I have a DataGridView bound to a list (descended from EditableRootListBase) of parents (descended from BusinessBase). I have a second DataGridView bound to a list (descended from BusinessListBase) of children (descended from BusinessBase). Both grids allow adding, editing and deleting. I am using CSLA 3.0.3 with VS2005.

The grids behave normally except for the following. If I am in the middle of editing a parent row and close the form, all changes are saved. This is the behaviour I want. If I am in the middle of editing the child row and close the form, the current changes to the child are not saved. I can work around the difference in behaviour by casting the parent object as an IEditableObject and calling the EndEdit method in a form closing event handler.

As far as I can tell I have coded all business objects as suggested in the documentation and code samples.

Has anyone any ideas on what I might have done wrong?

Regards,

Patrick Davey (Alias FatPigeon).

RockfordLhotka replied on Friday, January 11, 2008

In your UI code are you following the pattern shown in the 3.0 version of PTWin and described in Using CSLA .NET 3.0? It sounds like you are not properly unbinding the objects from the bindingsource controls before calling Save().

FatPigeon replied on Saturday, January 12, 2008

There is no code in the form except for setting the DataSource of the parent grid in the form constructor. I am relying on the BindingSource to do all the work as discussed in Binding to an Object - page 115 in Using CSLA .NET 3.0?. This seems to work fine for the parent grid all the time and fine for the child grid all the time except for when the form is closed while a child row is being edited.
 
If unsaved changes exist in the current child collection and the child grid still has focus, these are not saved if the form is closed, where as unsaved changes in the current row of the parent grid are saved when the form is closed.
 
Any thoughts?
 
Patrick
 

RockfordLhotka replied on Saturday, January 12, 2008

The binding is automatic. But if you look further in the data binding chapter you’ll see that you can’t call Save() until you have unbound the objects from the bindingsource controls. You must first unbind the child, then the parent. And unbinding takes a bit of code, especially for collections, because you must explicitly call CancelEdit() or EndEdit() on the child.

 

Rocky

 

 

From: FatPigeon [mailto:cslanet@lhotka.net]
Sent: Saturday, January 12, 2008 5:15 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] DataGridView Child not Saved on Form Close

 

There is no code in the form except for setting the DataSource of the parent grid in the form constructor. I am relying on the BindingSource to do all the work as discussed in Binding to an Object - page 115 in Using CSLA .NET 3.0?. This seems to work fine for the parent grid all the time and fine for the child grid all the time except for when the form is closed while a child row is being edited.

 

If unsaved changes exist in the current child collection and the child grid still has focus, these are not saved if the form is closed, where as unsaved changes in the current row of the parent grid are saved when the form is closed.

 

Any thoughts?

 

Patrick

 



FatPigeon replied on Sunday, January 13, 2008

Thanks very much for your help Rocky (even on a Weekend!) but there seems to be a bit of miss communication - I am not trying to call the save method.
 
I am relying on all the work you have put in to ensure that BusinessBase (from which the parent descends) implements  IEditableRoot and that the IEditableRoot.EndEdit in BusinessBase ultimately calls ApplyEditChild on the EditableRootListBase (the ancestor for the parent's containing collection) which calls SaveItem() which calls Save on the parent - which is absolutely wonderful and works fine - most of the time:
 
If I move from one parent to another in the parent's grid, all changes to the parent and children are saved, if I close the form while editing a parent all changes are saved, the only case where save is not called via the binding mechanism is when a child is being edited when the form is closed (and as I mentioned before there is a work-around for this).
 
I guess I must make clear that I am using the term parent and child in the application sense eg the parent may be an employer and the child may be a employee.
 
Are you saying that I should not be relying on this mechanism? It would be a big shame if I can't.
 
Regards,
 
Patrick

RockfordLhotka replied on Sunday, January 13, 2008

I see, sorry…

 

I have never tried to figure out the UI code necessary to use ERLB with child objects, so you are in uncharted territory.

 

But you can extrapolate from PTWin the fact that you’d need to unbind the child bindingsource before the root object could be saved. You aren’t calling Save(), but ERLB is calling Save(), so Save() is being called. The object (and its children) must be unbound before Save() can be called.

 

ERLB takes care of “unbinding” the object before Save() is called. But it doesn’t know that there are child objects involved, or child bindingsource objects. So you must detect that the root object is about to be saved, unbind the child bindingsource, allow the Save() call and then rebind the child bindingsource (probably to a new set of children from the new root).

 

Your manual EndEdit() call is more or less what I’m talking about, but it isn’t quite right. Where you do the EndEdit() call you need to actually unbind the child collection. Otherwise what happens is that your EndEdit() is immediately followed by an automatic BeginEdit(). Yes, your changes are saved, but that one child object is actually still at an elevated edit level, and there’ll almost certainly be some unpredictable end results if the user leaves a row (at the root leve), then returns to that row, because that row has one child already at edit level 1 or 2, which will be pushed yet higher if it is edited – in the end you’ll get some odd results.

 

To avoid that, where you are calling EndEdit(), replace that with a call to UnbindBindingSource() from PTWin, and then make sure to rebind once the Save() call is complete.

 

Rocky

 

 

From: FatPigeon [mailto:cslanet@lhotka.net]
Sent: Sunday, January 13, 2008 1:08 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: DataGridView Child not Saved on Form Close

 

Thanks very much for your help Rocky (even on a Weekend!) but there seems to be a bit of miss communication - I am not trying to call the save method.

 

I am relying on all the work you have put in to ensure that BusinessBase (from which the parent descends) implements  IEditableRoot and that the IEditableRoot.EndEdit in BusinessBase ultimately calls ApplyEditChild on the EditableRootListBase (the ancestor for the parent's containing collection) which calls SaveItem() which calls Save on the parent - which is absolutely wonderful and works fine - most of the time:

 

If I move from one parent to another in the parent's grid, all changes to the parent and children are saved, if I close the form while editing a parent all changes are saved, the only case where save is not called via the binding mechanism is when a child is being edited when the form is closed (and as I mentioned before there is a work-around for this).

 

I guess I must make clear that I am using the term parent and child in the application sense eg the parent may be an employer and the child may be a employee.

 

Are you saying that I should not be relying on this mechanism? It would be a big shame if I can't.

 

Regards,

 

Patrick



FatPigeon replied on Monday, January 14, 2008

Uncharted territory eh - that sounds interesting. Well I have done some exploring and have found the following:

Allowing the binding source to keep control works find – all data is saved when ever I move form one parent row to another. I have investigated the edit level issue that may occur on the child object but there does not seem to be a problem – the edit level is never more than one. After all, the BusinessBase implementation of IEditableObject.BeginEdit is designed to ignore all calls if BindingEdit is true, and BindingEdit is set the first time round.

Remember that the only code on the form is a bit in the constructor to set the DataSource of the parent BindingSource.

I do not understand why you are suggesting I should do any unbinding when the binding source always has control. Also, it seems a bit risky to do unbinding when the BindingSource is in the middle of calling IEditableObject.EndEdit on the business object. I can see that this is not the case in PTWin so you do need to unbind.

The original problem I had, and still have, is that IEditableObject.EndEdit does not get called on the parent by the binding source when the form is closed if the current children have some changes and a child row still has focus. IEditableObject.EndEdit does get called on the child object but this is of no use as it’s containing collection is not an EditableRootListBase. If this is the way the binding source/ERLB works then that’s ok – I can work around it.

However, if you think this whole approach is unreliable then I must think again. But this would be a shame as everything seems to work so well and the development technique was so elegant. All the UI was done using the form designer – very little code. And the result is a UI that is very common in ‘Power User’ type applications. Also, I have always had the feeling that this approach is what the BindingSource is all about – it makes full use of it.

Regards,

Patrick

FatPigeon replied on Tuesday, January 22, 2008

I know I am in uncharted territory and you have lot on your plate at the moment but I just thought I would make a note of an issue I have come across just in case you have time to look at it.

 

The issue concerns invoking a row undo with the Esc key when a datagridview is bound to an editable root list base. The undo works fine the first time a row is visited but does not seem to work on the second visit. This is only a problem with Csla 3.0.3. Using Csla 2.1.4 the undo works all the time.

 

Regards,

 

Patrick

RockfordLhotka replied on Tuesday, January 22, 2008

This is true with a simple ERLB where each root has no child objects?

 

Or to put it another way, there’s a project in svn in the samples/trunk/ERLBTest folder that I use for testing ERLB and data binding. I don’t have time to look in the near future, but if you could confirm the issue exists in that test app that’d be very helpful!

 

svn://svn.lhotka.net/csla/samples/trunk/ERLBTest

 

Rocky

 

 

From: FatPigeon [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 22, 2008 8:56 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: DataGridView Child not Saved on Form Close

 

I know I am in uncharted territory and you have lot on your plate at the moment but I just thought I would make a note of an issue I have come across just in case you have time to look at it.

 

The issue concerns invoking a row undo with the Esc key when a datagridview is bound to an editable root list base. The undo works fine the first time a row is visited but does not seem to work on the second visit. This is only a problem with Csla 3.0.3. Using Csla 2.1.4 the undo works all the time.

 

Regards,

 

Patrick



FatPigeon replied on Tuesday, January 22, 2008

Forgive my stupidity – I have navigated to http://www.lhotka.net/cslacvs/viewvc.cgi/samples/trunk/ERLBTest/

 

Which is what I assume is the same as

 

svn://svn.lhotka.net/csla/samples/trunk/ERLBTest

 

but cannot work out how to download it.

 

Regards,

 

Patrick

RockfordLhotka replied on Tuesday, January 22, 2008

No problem :)

 

You need to use something like TortoiseSVN to access the repository using the svn:// URI. That will allow you to do a checkout of the code to your machine.

 

http://www.lhotka.net/cslanet/Repository.aspx

 

Rocky

 

 

From: FatPigeon [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 22, 2008 11:31 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: RE: DataGridView Child not Saved on Form Close

 

Forgive my stupidity – I have navigated to http://www.lhotka.net/cslacvs/viewvc.cgi/samples/trunk/ERLBTest/

 

Which is what I assume is the same as

 

svn://svn.lhotka.net/csla/samples/trunk/ERLBTest

 

but cannot work out how to download it.

 

Regards,

 

Patrick



FatPigeon replied on Wednesday, January 23, 2008

Thanks for the pointer Rocky; I think I have solved it.

 

No your ERLBTest project does not exhibit the problem.

 

Your ERLBTest project had CslaAutoCloneOnUpdate set to True. As soon as I did this in my project the problem went away.

 

I think this is because the ERLB creates a clone of the business object in the SaveItem method if this config item is not set to true. The BindingEdit flag on the business object is set to false after the call to AcceptChanges in BusinessBase.ApplyEdit i.e. after the clone has been created. So the BindingEdit flag is still true in the cloned object that is now in the collection. Next time the row is visited a snap shot is not taken during the call to IEditableObject.BeginEdit as BindingEdit is still true.

 

Does this make sense? If so, is it easy to say why the ERLB takes this clone if CslaAutoCloneOnUpdate is not set?

 

Regards,

 

Patrick

RockfordLhotka replied on Wednesday, January 23, 2008

ERLB (and Csla.Wpf.CslaDataProvider) clones the object because the only safe way to save an object when using a local data portal is to save a clone.

 

CslaAutoCloneOnUpdate tells the data portal to do that clone, and the data portal can be smarter about it (because it knows whether the data portal is local or remote).

 

If you are using a local data portal and you don’t clone the object before saving, then any exception that occurs during the save will leave your object in an indeterminate state. In earlier versions of CSLA I didn’t force the cloning for performance reasons – but the resulting behavior is incorrect, and so I’m phasing in the requirement to do the cloning. In CSLA 3.5 the auto-clone behavior is turned on by default (the reverse of 3.0 where it is off, but you can and should turn it on).

 

Rocky

 

 

From: FatPigeon [mailto:cslanet@lhotka.net]
Sent: Wednesday, January 23, 2008 7:12 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: RE: RE: DataGridView Child not Saved on Form Close

 

Thanks for the pointer Rocky; I think I have solved it.

 

No your ERLBTest project does not exhibit the problem.

 

Your ERLBTest project had CslaAutoCloneOnUpdate set to True. As soon as I did this in my project the problem went away.

 

I think this is because the ERLB creates a clone of the business object in the SaveItem method if this config item is not set to true. The BindingEdit flag on the business object is set to false after the call to AcceptChanges in BusinessBase.ApplyEdit i.e. after the clone has been created. So the BindingEdit flag is still true in the cloned object that is now in the collection. Next time the row is visited a snap shot is not taken during the call to IEditableObject.BeginEdit as BindingEdit is still true.

 

Does this make sense? If so, is it easy to say why the ERLB takes this clone if CslaAutoCloneOnUpdate is not set?

 

Regards,

 

Patrick



Copyright (c) Marimer LLC