I've the following situation
Model : Editable Root Parent (e.g. Shoe123)
ModelColors : EditableChildList (e.g. we have two items black, gold)
ModelColor : EditableChild
Articles : EditableChildList (e.g.
Article : EditableChild
Barcode: 2000000001029 ,Size: 36 Price: 88 EUR, Color: black
Barcode: 2000000001036 ,Size: 37 Price: 88 EUR, Color: black
Barcode: 2000000001043 ,Size: 36 Price: 99EUR, Color: gold
Barcode: 2000000001050 ,Size: 37 Price: 99 EUR, Color: gold
In the following case I receive the error : Edit level mismatch in CopyState
Edit e.g. the first record for the first color (Barcode: 2000000001029 ,Size: 36 Price: 88 EUR, Color: black)
Click Cancel. Until now everything goes fine.
Edit e.g. the first record for the second color ( Barcode: 2000000001043 ,Size: 36 Price: 99EUR, Color: gold)
Click Cancel. Now I receive the error.
I've implemented the code as in the project tracker example.
I've tested it first with version : 3.0.2 and there I have also the same problem.
I've tested it also with version cslacs-3.0.4-080222 and I have the same problem.
Below you can find the code for the method RebindUI:
Until one level I don't have any problems, but now I have two levels:
Parent, ChildCollection, GrandChildCollection
and since then I'm having problems.
I now you have to be carefull in the order you unbind. So that's the reason I've included the code.
Can you have a look at it?
private void RebindUI(bool saveObject, bool rebind){
// disable events this.modelBindingSource.RaiseListChangedEvents = false; this.modelColorsBindingSource.RaiseListChangedEvents = false; this.articlesBindingSource.RaiseListChangedEvents = false; try{
// unbind the UIUnbindBindingSource(
this.articlesBindingSource, saveObject, false);UnbindBindingSource(
this.modelColorsBindingSource, saveObject, false);UnbindBindingSource(
this.modelBindingSource, saveObject, true); this.modelColorsBindingSource.DataSource = this.modelBindingSource; this.articlesBindingSource.DataSource = this.modelColorsBindingSource; // save or cancel changes if (saveObject){
_model.ApplyEdit();
try{
Model temp = _model.Clone();_model = temp.Save();
}
catch (Csla.DataPortalException ex){
MessageBox.Show(ex.BusinessException.ToString(), "Error saving", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);}
catch (Exception ex){
MessageBox.Show(ex.ToString(), "Error Saving", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);}
}
else_model.CancelEdit();
// rebind UI if requested if (rebind)BindUI();
}
finally{
// restore events this.modelBindingSource.RaiseListChangedEvents = true; this.modelColorsBindingSource.RaiseListChangedEvents = true; this.articlesBindingSource.RaiseListChangedEvents = true; if (rebind){
// refresh the UI if rebinding this.modelBindingSource.ResetBindings(false); this.modelColorsBindingSource.ResetBindings(false); this.articlesBindingSource.ResetBindings(false);}
}
}
Look at the code from this sample:
http://www.lhotka.net/cslacvs/viewvc.cgi/samples/trunk/RootChildGrandchildWinFormTest/
This sample is a little test project I put together around data binding to grandchild objects, and it might be helpful to you. You can also pull the code completely from the repository if you'd like.
I've looked at your example. Great, I didn't know that you have created a new example. I knew only about the deepdata example.
I've studied your example and I found the magic line of code which solves the problem:
void childrenBindingSource_CurrentChanged(object sender, EventArgs e)
{
this.grandchildrenBindingSource.EndEdit();}
In your ProjectTracker example you don't have this.
Rocky. Can you explain a bit more the reason of this? Is it not possible to put this in the framework?
As workaround I had found the following solution:
public Grandchild(){
DisableIEditableObject =
true;...
}
With this the GUI doesn't have to do anything. But maybe you know some disadvantages for this implementation?
Some remarks:
1) I had to initialize the variable _name to string.Empty otherwise the example is not working
string
_name = string.Empty;2)
Creating a new root doesn't work. You can click on the + on the navigator, but saving and cancelling doesn't work.
It is the responsibility of the UI (data binding really) to call
the IEditableObject interface appropriately. Unfortunately data binding doesn’t
seem to handle grandchild objects particularly well, because it doesn’t
cascade the EndEdit calls down like you’d expect.
In fact, data binding doesn’t provide any indication that
currency has changed at the grandchild level (it does at the child level oddly)
and so something needs to handle that. Since the business layer isn’t
even notified of such a currency change, I don’t know of a way to
automate this within CSLA itself.
What you are doing with DisableIEditableObject works because you
are blocking data binding from doing its BeginEdit. That is probably fine as
long as your users don’t expect to be able to use in-place editing in a
grid for those grandchild objects. Some things won’t work with this
setting - most obviously having the user press ESC to undo changes in a row,
but there could be others – I’m not sure.
Rocky
From: alef
[mailto:cslanet@lhotka.net]
Sent: Tuesday, February 26, 2008 9:47 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Bug in Undo: Edit level mismatch in CopyState
in version cslacs-3.0.4-080222
I've looked at your example. Great, I didn't know that you have created a
new example. I knew only about the deepdata example.
I've studied your example and I found the magic line of code which solves
the problem:
void childrenBindingSource_CurrentChanged(object sender, EventArgs e)
{
this.grandchildrenBindingSource.EndEdit();
}
In your ProjectTracker example you don't have this.
Rocky. Can you explain a bit more the reason of this? Is it not possible to
put this in the framework?
As workaround I had found the following solution:
public Grandchild()
{
DisableIEditableObject = true;
...
}
With this the GUI doesn't have to do anything. But maybe you know some
disadvantages for this implementation?
Some remarks:
1) I had to initialize the variable _name to string.Empty otherwise the
example is not working
string _name = string.Empty;
2)
Creating a new root doesn't work. You can click on the + on the navigator,
but saving and cancelling doesn't work.
Thanks for the explanation.
In the VB world I tried to avoid the binding as much as possible. I thought in .NET everything is solved, but apparently not. Oh the binding stays a tough issue.
In the following case I still have a problem with the example (besides the problems I explained in the previous mail):
delete a child object
click on cancel
You'll receive the error "Edit level mismatch in CopyState".
Rocky, do you now the magic line of code to solve this?
Data binding has its quirks - no doubt about it. But there is a such a huge code savings by using data binding compared to doing it yourself (and I don't know that you can replacate in-place grid editing without data binding in any case), that it is worth figuring out.
Your edit level mismatch exception is due to some asymmetry. Every BeginEdit call must have a corresponding CancelEdit/EndEdit. You are just missing one somewhere.
I detected that your example was still using version 3.0.2.
I've upgraded it to cslacs-3.0.4-080222 and then I don't have this problem anymore.
Great.
You changed something to solve this, because I didn't changed anything in your example code?
Probably. I know there were a couple data binding fixes in 3.0.3
and 3.0.4 (see the change logs) and it is quite likely that one of them
addressed this issue.
Rocky
From: alef
[mailto:cslanet@lhotka.net]
Sent: Monday, March 03, 2008 9:05 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Bug in Undo: Edit level mismatch in
CopyState in version cslacs-3.0.4-080222
I detected that your example was still using version 3.0.2.
I've upgraded it to cslacs-3.0.4-080222 and then I don't have this
problem anymore.
Great.
You changed something to solve this, because I didn't changed anything in
your example code?
Copyright (c) Marimer LLC