views:

364

answers:

2

I have a nasty exception that seems to occure deep inside the DataGridView Code.

I have a class that inherits from BindingList which is the DataSource of a BindingSource which is the DataSoure of a DataGridView.

Under some strange circumstances I get an exception during the overridden OnListChanged() method of my class:

    protected override void OnListChanged(ListChangedEventArgs e)
    {
        base.OnListChanged(e); // <-- ArgumentOutOfRangeException
                               // ...Parametername: rowIndex
    }

the stacktrace looks like this:

    bei System.Windows.Forms.DataGridView.GetCellDisplayRectangle(Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow)
    bei System.Windows.Forms.DataGridView.GetCellAdjustedDisplayRectangle(Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow)
    bei System.Windows.Forms.DataGridView.InvalidateCellPrivate(Int32 columnIndex, Int32 rowIndex)
    bei System.Windows.Forms.DataGridView.OnCellCommonChange(Int32 columnIndex, Int32 rowIndex)
    bei System.Windows.Forms.DataGridView.DataGridViewDataConnection.ProcessListChanged(ListChangedEventArgs e)
    bei System.Windows.Forms.DataGridView.DataGridViewDataConnection.currencyManager_ListChanged(Object sender, ListChangedEventArgs e)
    bei System.Windows.Forms.CurrencyManager.OnListChanged(ListChangedEventArgs e)
    bei System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
    bei System.Windows.Forms.BindingSource.OnListChanged(ListChangedEventArgs e)
    bei System.Windows.Forms.BindingSource.InnerList_ListChanged(Object sender, ListChangedEventArgs e)
    bei System.ComponentModel.ListChangedEventHandler.Invoke(Object sender, ListChangedEventArgs e)
    bei System.ComponentModel.BindingList`1.OnListChanged(ListChangedEventArgs e)
    bei My.Own.BindingList.OnListChanged(ListChangedEventArgs e)

Well, I could just add a try\catch exception around this, but I am curious why this happens at all.

Someone told me one time, I could use the mighty power of reflections and System.Diagnostics.StackTrace to get the StackFrame which causes the exception (That works so far) and inspect the parameters (I have no clue how to do this) which would help me, beause if I know the value from rowindex / columnindex I could track down the exception.

Can anybody tell me, if possible at all, to get the Parameters from the Exception?

Thanks in advance!

Update:

The problem seems to be related to some threading issues and has nothing to do with the rowIndex. BindingList is the datasource of an DataGridView. If I add an Element to the list the OnListChanged event fires, which causes the dataGridView to load the databound properties from the new instance of T. In the getter of one property I had some code that changed another property which caused the OnPropertyChanged Event of the T instace to be fired.

Just one simple lock(this) in the BindingList Add method like here: http://stackoverflow.com/questions/148587/has-anyone-written-a-thread-safe-bindinglistt solved the problem for me. Hard to debug ;(

+1  A: 

Unfortunately you can't get the argument values from the stacktrace or exception.

There are various properties available on the ListChangedEventArgs parameter that might help with debugging: ListChangedType, NewIndex, OldIndex and PropertyDescriptor.

LukeH
+2  A: 

At first sight (and second and third sight), Luke is right, but looking further there might be a way. The problem using a straight approach through the StackTrace class doesn't work, simply because that class stores the stack information, including the parameter info, but not the parameter data.

This data would be available in a debugging version, not in a release version. To get to that data, you can interact with the debugger of visual studio. You can do so programmatically. However, I think it is easier to call Debugger.Break() (and possibly checking whether there's a debugger attached first) and then do the analysis.

To interact with the IDE and the debugger, here's an answer that explains how (it explains how to set breakpoints programmatically but does so by interacting with the IDE).

To find the information you're after, you can use the automation methods that would be available when you're in the IDE writing a macro. It would be easier if you could reflect your way to the objects on the heap, and possibly there is one, but this is the only workable method I could find so far.

Abel
I can reproduce this error within my visual studio IDE. The problem is that the DataGridView seems to "listen" to the BindingList<T> ListChanged Event and causes the Exception to happen when my Property "Prop1" changes. Prop1 has rowId 3 in the Grid, so I am curious why I get the ArgumentOutOfRangeException and wanted to know what is the value of rowId in the Method GetCellDisplayRectangle(...) on top of the stack.
SchlaWiener
If you get the exception during debugging, open the Call Stack window and doubleclick the line with `GetCellDisplayRectangle()` in the stack. Hover your mouse over the variable or parameter `rowId` in that function and you'll be able to see its value. Alternatively, you can create a conditional breakpoint *before* the exception occurs, to break in that function on `rowId==3`. To do so, make a breakpoint `GetCellDisplayRectangle`, rightclick it, select "Condition" and type "rowId==3" in the Condition dialog box. To automate either process is possible, but hard, as the link in my answer shows.
Abel