Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erratic InvalidOperationException on datagridview

My Winform app is logging AppDomain.CurrentDomain.UnhandledException and Application.ThreadException at the root level, and I got this exception:

System.InvalidOperationException: Operation is not valid due to the current state of the object. at System.Windows.Forms.DataGridView.DataGridViewDataConnection.ProcessListChanged(ListChangedEventArgs e) at System.Windows.Forms.DataGridView.DataGridViewDataConnection.currencyManager_ListChanged(Object sender, ListChangedEventArgs e) at System.Windows.Forms.CurrencyManager.OnListChanged(ListChangedEventArgs e) at System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e) at System.ComponentModel.BindingList1.OnListChanged(ListChangedEventArgs e) at System.ComponentModel.BindingList1.FireListChanged(ListChangedType type, Int32 index) at System.ComponentModel.BindingList1.InsertItem(Int32 index, T item) at System.Collections.ObjectModel.Collection1.Add(T item) at System.ComponentModel.BindingList1.AddNewCore() at System.ComponentModel.BindingList1.System.ComponentModel.IBindingList.AddNew() at System.Windows.Forms.CurrencyManager.AddNew() at System.Windows.Forms.DataGridView.DataGridViewDataConnection.AddNew() at System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnNewRowNeeded() at System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell& dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean canCreateNewRow, Boolean validationFailureOccurred) at System.Windows.Forms.DataGridView.SetCurrentCellAddressCore(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick) at System.Windows.Forms.DataGridView.ProcessDownKeyInternal(Keys keyData, Boolean& moved) at System.Windows.Forms.DataGridView.ProcessEnterKey(Keys keyData) at System.Windows.Forms.DataGridView.ProcessDialogKey(Keys keyData) at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData) at System.Windows.Forms.TextBoxBase.ProcessDialogKey(Keys keyData) at System.Windows.Forms.Control.PreProcessMessage(Message& msg) at System.Windows.Forms.Control.PreProcessControlMessageInternal(Control target, Message& msg) at System.Windows.Forms.Application.ThreadContext.PreTranslateMessage(MSG& msg)

This is the result of ex.ToString(), and it returns no custom code of my app, only internal System.Windows.Forms methods.

The exception is raised time to time on some customer machine, I'm even not able to reproduce it myself.

This smell not good, and my assumption was something when I change the datasource bounding of the datagridview. But in this case I should see at least my class in the exception stack, but here nothing.

Any clue to find the root cause, or to debug that?

Many thanks

like image 648
Chris Avatar asked Oct 30 '22 13:10

Chris


2 Answers

If you investigate the stack trace, you'll see the root of the problem: customer is trying to add a new record on the grid, so the event handler tries to add the record to the datasource, which lead to another event handler, which tries to add a record to the binding list, which lead to event currencyManager_listChanged firing up, which fails due to wrong state of the object.

Either you dispose your list or you do not unsubscribe from the events of the disposed control.

like image 166
VMAtm Avatar answered Nov 15 '22 04:11

VMAtm


I've experienced exactly the same exception, and it occurs after the user deletes multiple rows (multi select enabled), and includes the last row in the selection. The last row is for adding new items. Everything works fine, until the user then goes to edit remaining rows, and the exception occurs.

When the user doesn't include the last/add new item row in the selection, everything works fine after the delete.

I haven't had time to investigate exactly why this behavior occurs, but the work around was to not allow the add new item row to be included when multi-selecting items, which can be detected by the IsNewRow property of DataGridViewRow and then calling ClearSelection() on the DataGridView if this row is in the selection.

private void DataGridView1_SelectionChanged(object sender, EventArgs e)
{
    foreach (DataGridViewRow row in dataGridView1.SelectedRows)
    {
        if (row.IsNewRow)
        {
            dataGridView1.ClearSelection();
            return;
        }
    }
}
like image 31
TheBugger Avatar answered Nov 15 '22 04:11

TheBugger