CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

Error when pressing escape key on a filtered list bound datagridview

Answered (Not Verified) This post has 0 verified answers | 7 Replies | 3 Followers

Not Ranked
13 Posts
Helius posted on Fri, Jan 11 2013 10:53 AM

In my Windows Form Application i have a datagridview bound to an Editable Child List representing a list of tariffs. I have some custom filters implemented through comboboxes and based on the values i select i build a filtered list for the tariffs.

        Dim mFiltered As New Csla.FilteredBindingList(Of ApTariff)(oApmailItemCharacteristic.ApTariffs)

        mFiltered.FilterProvider = AddressOf FilterTariff
        mFiltered.ApplyFilter("", oCriteria)
        Dim mSortedTariff As New SortedBindingList(Of ApTariff)(mFiltered)
        mSortedTariff.ApplySort("WeightFrom", ListSortDirection.Ascending)
        ApTariffsBindingSource.DataSource = mSortedTariff

The save for the object graph is working ok when editing existing rows on the tariffs grid, but when i try to add new rows i got an error of type "Edit Level Mismatch"

Also if the datagridview is empty because of the selection from comboboxes  and i try to add a new row and press the escape key i got the following error:

System.ArgumentOutOfRangeException was unhandled
  Message=Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
  Source=mscorlib
  ParamName=index
  StackTrace:
       at System.ThrowHelper.ThrowArgumentOutOfRangeException()
       at System.Collections.Generic.List`1.get_Item(Int32 index)
       at Csla.FilteredBindingList`1.OriginalIndex(Int32 filteredIndex)
       at Csla.FilteredBindingList`1.System.ComponentModel.ICancelAddNew.CancelNew(Int32 itemIndex)
       at Csla.SortedBindingList`1.System.ComponentModel.ICancelAddNew.CancelNew(Int32 itemIndex)
       at System.Windows.Forms.BindingSource.System.ComponentModel.ICancelAddNew.CancelNew(Int32 position)
       at System.Windows.Forms.CurrencyManager.CancelCurrentEdit()
       at System.Windows.Forms.DataGridView.DataGridViewDataConnection.CancelRowEdit(Boolean restoreRow, Boolean addNewFinished)
       at System.Windows.Forms.DataGridView.CancelEditPrivate()
       at System.Windows.Forms.DataGridView.CancelEdit(Boolean endEdit)
       at System.Windows.Forms.DataGridView.ProcessEscapeKey(Keys keyData)
       at System.Windows.Forms.DataGridView.ProcessDataGridViewKey(KeyEventArgs e)
       at System.Windows.Forms.DataGridView.OnKeyDown(KeyEventArgs e)
       at System.Windows.Forms.Control.ProcessKeyEventArgs(Message& m)
       at System.Windows.Forms.DataGridView.ProcessKeyEventArgs(Message& m)
       at System.Windows.Forms.Control.ProcessKeyMessage(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.DataGridView.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at MHS.Desktop.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

 

 

 

 

All Replies

Top 10 Contributor
1,764 Posts

Which version of CSLA do you use? 

In windows forms it is essential to bind/unbind properly before calling Save. This is the most common reason for EditLevelMismatch Exception.

See my post: http://jonnybekkum.wordpress.com/2009/10/20/forms-databinding-the-magic-sequence-of-binduiunbindui/

Jonny Bekkum, Norway CslaContrib Coordinator

Not Ranked
13 Posts
Helius replied on Sun, Jan 13 2013 5:23 AM

Hi Jonny, 

I have tried with the latest version of CSLA 4.5,  and the problem persists. I am using CSLAExtender to manage the  bind/unbind of bindingsources. The save is working ok when i filter, edit data in the grid, filter, edit again and save in the end. The problem occurs only when i try to add any new rows in the filtered datagrid. 

Also there is that problem when adding a new row in the empty datagrid, and directly pressing ok. I think may be these two errors are related, and probably i am missing something there.

 

Not Ranked
5 Posts
Cymro replied on Tue, May 14 2013 6:32 AM

I get this too...but I don't think it is an "Edit Level Mismatch" type exception.  I believe that the issue is in the FilteredBindingList (and posibly the SortedBindingList) implementation of ICancelAddNew.CancelNew (which is called by the DataGridView binding).  

For some reason the DataGridView calls CancelNew with an index of -1 when the list is empty. and this causes an issue in the FilteredBindingList.OriginalIndex function.  It attempts to find the OriginalIndex based on an index of -1.

 void ICancelAddNew.CancelNew(int itemIndex)
    {
      ICancelAddNew can = _list as ICancelAddNew;
      if (can != null)
        can.CancelNew(OriginalIndex(itemIndex));
      else
        _list.RemoveAt(OriginalIndex(itemIndex));
    }

  private int OriginalIndex(int filteredIndex)
    {
      if (_filtered)
        return _filterIndex[filteredIndex].BaseIndex;
      else
        return filteredIndex;
    }

 This can be replicated very easily by binding a FilteredBindingList to a DataGridView with DataGridView.AllowUserToAddRows = True.  Apply a filter to the list which will cause the grid to be empty, click in the new row and then press escape.  You should get a System.ArgumentOutOfRangeException.

Not Ranked
5 Posts
Answered (Not Verified) Cymro replied on Tue, May 14 2013 6:38 AM

I just checked the implementation of CancelNew in the SortedBindingList and this is Ok...I believe the missing line of code needs adding to the FilteredBindingList implementation...

void ICancelAddNew.CancelNew(int itemIndex)
    {
      //if (itemIndex > -1) return;
      if (itemIndex <= -1) return;

      ICancelAddNew can = _list as ICancelAddNew;
      if (can != null)
        can.CancelNew(OriginalIndex(itemIndex));
      else
        _list.RemoveAt(OriginalIndex(itemIndex));
    }

Edit: I don't think the SortedBindingList implementation was right either! I've switched the condition and this seems to be Ok now.

Top 25 Contributor
450 Posts

Hi Cymro,

I feel a bit lost after your edit comment. The fix below applies to SortedBindingList.

Right?

The fixed line is missing on FilteredBindingList.

Right?

Cymro:

void ICancelAddNew.CancelNew(int itemIndex)
    {
      //if (itemIndex > -1) return;
      if (itemIndex <= -1) return;

      ICancelAddNew can = _list as ICancelAddNew;
      if (can != null)
        can.CancelNew(OriginalIndex(itemIndex));
      else
        _list.RemoveAt(OriginalIndex(itemIndex));
    }

 

 

Tiago Freitas Leal, CslaGenFork (Open Source CSLA code generator)

Not Ranked
5 Posts
Cymro replied on Wed, May 15 2013 2:33 AM

Hi Tiago,

Yes in our current version of CSLA - 4.0, the line was completely missing from FilteredBindingList and incorrect in the SortedBindingList.  The implementation of this method should be the same in both classes.

Not Ranked
5 Posts
Cymro replied on Thu, May 16 2013 9:13 AM

I have tested this further and it appears that there are other issues around the CancelNew behaviour with a DataGridView.  The reason I was looking at this was because we are attempting to use a SortedBindingList and FilteredBindingList with a DynamicBindingListBase derived class.  The issue here is that when the list is Sorted (or filtered) the cancel new fails and leaves the invalid new item in the list.

I have tracked this down and found the issue but not a satisfactory resolution Tongue Tied

When a new row is added to a DataGridView the AddNew adds the object to the end of the list.  Even if the sorted is list is sorted it still goes at the end of the sorted list (which is what we want).

The issue is with the way that the DataGridView's DataBinding handles the cancelling. 

  1. The DataGridView calls CancelEdit on the child object through (IEditableObject.CancelEdit). 
  2. The changes get rolled back in the child object, but this has the side effect of raising OnUnknownPropertyChanged.
  3. PropertyChanged is handled by the parent BindingList and raises the IBindingList.ListChanged event with a ListChangeType of "Reset". 
  4. The SortedBindingList handles the ListChanged of the source list and calls DoSort, resorting all the items in the list (including the new item).  This is where the problem lies!!!
  5. The DataGridView then calls ICancelAddNew.CancelNew passing the last row index - but this is no longer where our item is, because it has been re-sorted into the middle of the list somewhere.

We do not see the effect of this issue in a BusinessBindingListBase because as part of the CancelEdit on the child, it calls to the parent list to remove it (when the EditLevel < EditLevelAdded) using IParent.RemoveChild(T child).  With a BusinessBindingListBase the implementation of this method removes the child, whereas with a DynamicBindingList does not.  Therefore, with a BusinessBindingListBase the new child is removed from the list before the CancelNew is even called (as part of step 2 above) which masks the issue with the CancelNew implementation of the SortedBindingList.

I am unhappy with this "fix" for two reasons. Firstly, the original comment in the method...

...suggests that this was thought abount and decided this should not be done here.  And secondly because this just masks the real issue of the list getting re-sorted during the whole cancel process.

Now the obvious "fix" is to have the DynamicBindingList remove the child as part of the IParent.RemoveChild implementation as follows...

    /// <summary>
    /// This method is called by a child object when it
    /// wants to be removed from the collection.
    /// </summary>
    /// <param name="child">The child object to remove.</param>
    void Core.IEditableCollection.RemoveChild(Csla.Core.IEditableBusinessObject child)
    {
      Remove((C)child);
    }

I am unhappy with this "fix" for two reasons. Firstly, the original comment in the method...

      // do nothing, removal of a child is handled by
      // the RemoveItem override

...suggests that this was thought abount and decided this should not be done here. And secondly because this just masks the real issue of the list getting re-sorted during the whole cancel process.  Does anyone have any thoughts?

Page 1 of 1 (8 items) | RSS

Copyright (c) 2006-2010 Marimer LLC. All rights reserved.
Email admin@lhotka.net for support.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems