Sorting/Filtering

Sorting/Filtering

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


JasonG posted on Monday, December 10, 2012

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

 

 

JonnyBee replied on Monday, December 10, 2012

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?

JasonG replied on Wednesday, December 12, 2012

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

 
public void Rebind(Child child)
        {
            _child = child;
            childBindingSource.DataSource =  _child;          
 
        }

the GrandChildbindingSource.datasource is bound to childBindingSource

JasonG replied on Wednesday, December 12, 2012

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?

JasonG replied on Wednesday, December 12, 2012

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();

                }

}

JonnyBee replied on Wednesday, December 12, 2012

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

 

 

JasonG replied on Wednesday, December 12, 2012

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.

JonnyBee replied on Friday, December 14, 2012

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 (objectnull;
        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((IFormatProviderCultureInfo.CurrentCulture)         }));       }       set       {         if (index < 0 || index >= this.list.Count)           throw new IndexOutOfRangeException(System.Windows.Forms.SR.GetString("ListManagerNoValue"new object[1]           {             (object) index.ToString((IFormatProviderCultureInfo.CurrentCulture)           }));         else           this.list[index] = value;       }     }

The end result is:

Copyright (c) Marimer LLC