Hey, I'm having problems sorting and saving. If I apply a sort to a BLB and then save i get an "edit level mismatch error". I've tried this scenario with v4.1 and 4.5, but i get the same error.
There has been much discussion on this topic, but nothing recently so has it been resolved? One post mentioned that v4.x should fix the problem, but I get the same error with all versions.
thanks,
Jason
I assume we are talking Windows forms here?
This is usually the result of not doing a proper unbind from the UI before calling Save.
Could you provide us a small sample to reproduce the behavior?
Sorry, yes I'm refering to Windows forms. The object model look like this, Parent > Child > Grandchild
Yes, I was getting the same error before, then I discovered that I wasn't unbinding a child control. With that fixed everything works ok.
But if I bind the grandchild datasource to a property of SortedBindingList<GrandChild> then apply a sort then save I get the "edit level mismatch error".
After doing more troubleshooting this is what I found.
After the UI is loaded and not doing anything else I click on a column header to apply a sort, to the first list of grandchildren. Then i click save, before the "parent.applyedit()", I notice that the first GrandChild in the list that a sort was applied had an editLevel of 2, where has all the other objects had an edit level of 1. If I sort the children on the second Child then the first grandchild in that child has an edit level of 2. I guess that object with an edit level of 2 is causing the problem, but why?
parent.EditLevel = 1
parent.Child[0].EditLevel = 1
parent.Child[0].GrandChild[0].EditLevel = 2
parent.Child[1].EditLevel = 1
parent.Child[1].GrandChild[0].EditLevel = 1
Here is the section of the code that i think is signifcant.
This segment of code is from the a winpart control that accept a parent object. Each child of the parent has its own child winpart that accept a Grandchild ojbect. The Grandchild winpart is added to tabpage that is then added to a tabcontrol on the Child winpart. So that each Child will have a tab with its own children display in a datagrid.
private void RebindUI(bool saveObject, bool rebind)
{
// disable events
try
{
foreach (TabPage page in this.ChildrenTabControl.TabPages)
{
ChildrenEdit comp = (ChildrenEdit)page.Controls[0];
comp.ChildrensBindingSource.RaiseListChangedEvents = false;
comp.GrandchildrenBindingSource.RaiseListChangedEvents = false;
UnbindBindingSource(comp.ChildrensBindingSource, saveObject, false);
UnbindBindingSource(comp.GrandchildrenBindingSource, saveObject, false);
}
if (saveObject)
{
_parent.ApplyEdit();
try
{
_parent = _parent.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
_parent.CancelEdit();
}
finally
{
if (rebind)
{
_parent.BeginEdit();
foreach (TabPage page in this.parentChildrensTabControl.TabPages)
{
ChildrenEdit child = (ChildrenEdit)page.Controls[0];
child.Rebind(_parent.Childrens[this.parentChildrensTabControl.TabPages.IndexOf(page)]); See below
}
}
// restore events
foreach (TabPage page in this.parentChildrensTabControl.TabPages)
{
ChildrenEdit comp = (ChildrenEdit)page.Controls[0];
comp.ChildrensBindingSource.RaiseListChangedEvents = true;
comp.GrandchildrenBindingSource.RaiseListChangedEvents = true;
}
if(rebind)
foreach (TabPage page in this.parentChildrensTabControl.TabPages)
{
ChildrenEdit comp = (ChildrenEdit)page.Controls[0];
comp.ChildrensBindingSource.ResetBindings(false);
comp.GrandchildrenBindingSource.ResetBindings(false);
}
}
}
private void BindUI()
{
_parent.BeginEdit();
foreach (Child item in _parent.Children)
{
TabPage page = new TabPage(item.Name);
this.parentChildrensTabControl.TabPages.Add(page);
ChildrenEdit comp = new ChildrenEdit(item);
comp.Dock = DockStyle.Fill;
page.Controls.Add(comp);
}
}
comp.Rebind
the GrandChildbindingSource.datasource is bound to childBindingSource
after more trouble shooting..
When sorting a datagird the edit level for the current grandchild is increased by one. But the problem seems to be when I call the UnbindBindingSoure. The grandchild binding source that is pass to the UnbindBindingSource is not the grandchild with the elevate editlevel but the, now current grandchild. This makes since, but how do I call EndEdit() on the grandchild with the elevated editlevel?
not sure if this is correct but I found a solution. In the Grandchild winpart i added..
private void grandChildDataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if(e.RowIndex == -1) //column header clicked
if(!(this.grandChildBindingSource.Current == null))
{
System.ComponentModel.IEditableObject current = grandChildBindingSource.Current as System.ComponentModel.IEditableObject;
current.EndEdit();
}
}
That should do it - however, you may be safer by changing from:
if(!(this.grandChildBindingSource.Current == null))
to
if(!(this.grandChildBindingSource.Postion > -1))
As trying to access Current property will throw an exception if Postition = -1
thanks for the tip. I assume to meant to remove the "!"?
So, you don't see anything wrong with how I'm unbinding/binding the UI from the datasources? Would there be a better/easier way?
Thanks.
No - I meant to check the value of property Position rather than Current != null.
Trying to access Current when Position == -1 will throw an Exception.
This is the code from BindingSource:
[Browsable(false)] public object Current { get { if (this.currencyManager.Count <= 0) return (object) null; else return this.currencyManager.Current; } }
And in CurrencyManager:
public override object Current { get { return this[this.Position]; } }
internal object this[int index] { get { if (index >= 0 && index < this.list.Count) return this.list[index]; throw new IndexOutOfRangeException(System.Windows.Forms.SR.GetString("ListManagerNoValue", new object[1] { (object) index.ToString((IFormatProvider) CultureInfo.CurrentCulture) })); } set { if (index < 0 || index >= this.list.Count) throw new IndexOutOfRangeException(System.Windows.Forms.SR.GetString("ListManagerNoValue", new object[1] { (object) index.ToString((IFormatProvider) CultureInfo.CurrentCulture) })); else this.list[index] = value; } }
The end result is:
Copyright (c) Marimer LLC