Bizarre IndexOutOfRangeException during Fill

J

Jon Skeet [C# MVP]

We've had a problem we've been trying to reproduce for weeks now. It
only occurs every so often, but we can't work out when, why, or how to
fix it.

We have various forms with CurrencyManagers in. The CurrencyManagers
are bound to DataViews which have been populated from the database. The
database itself is then changed from another thread, and then from the
UI thread we call Fill on the DataAdapter, passing in the DataTable
that the DataView is reflecting. Sometimes, we then get an exception
with the following stack trace (extra line between each stack frame for
clarity):

System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.
_ChangeRecordState(int nPositionNew = -1, bool fValidating = true, bool
fEndCurrentEdit = true, bool fFirePositionChange = true, bool fPullData
= false) + 0x34 bytes

System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.
_List_ListChanged(System.Object sender = {System.Data.DataView},
System.ComponentModel.ListChangedEventArgs e =
{System.ComponentModel.ListChangedEventArgs}) + 0x335 bytes

System.Data.dll!System.Data.DataView.OnListChanged
(System.ComponentModel.ListChangedEventArgs e =
{System.ComponentModel.ListChangedEventArgs})

System.Data.dll!System.Data.DataView.IndexListChanged
(System.Object sender = {System.Data.Index},
System.ComponentModel.ListChangedEventArgs e =
{System.ComponentModel.ListChangedEventArgs}) + 0xd bytes

System.Data.dll!System.Data.DataView.FireEvent
(System.Data.TargetEvent targetEvent = IndexListChanged, System.Object
sender = {System.Data.Index}, System.EventArgs e =
{System.ComponentModel.ListChangedEventArgs}) + 0x26 bytes

System.Data.dll!System.Data.DataViewListener.IndexListChanged
(System.Object sender = {System.Data.Index},
System.ComponentModel.ListChangedEventArgs e =
{System.ComponentModel.ListChangedEventArgs}) + 0x1d bytes

System.Data.dll!System.Data.Index.OnListChanged
(System.ComponentModel.ListChangedEventArgs e =
{System.ComponentModel.ListChangedEventArgs}) + 0x1d bytes

System.Data.dll!System.Data.Index.RecordStateChanged(int
oldRecord = 1, System.Data.DataViewRowState oldOldState = Unchanged,
System.Data.DataViewRowState oldNewState = ModifiedOriginal, int
newRecord = 19, System.Data.DataViewRowState newOldState = None,
System.Data.DataViewRowState newNewState = ModifiedCurrent) + 0xdc
bytes

System.Data.dll!System.Data.DataTable.RecordStateChanged(int
record1 = 1, System.Data.DataViewRowState oldState1 = Unchanged,
System.Data.DataViewRowState newState1 = ModifiedOriginal, int record2
= 19, System.Data.DataViewRowState oldState2 = None,
System.Data.DataViewRowState newState2 = ModifiedCurrent) + 0x38 bytes

System.Data.dll!System.Data.DataTable.SetNewRecord
(System.Data.DataRow row = {System.Data.DataRow}, int proposedRecord =
19, System.Data.DataRowAction action = Change, bool isInMerge = false)
+ 0xf1 bytes

System.Data.dll!System.Data.DataTable.LoadDataRow(System.Object[]
values = {Length=36}, bool fAcceptChanges = false) + 0x6f bytes

System.Data.Common.dll!
System.Data.Common.SchemaMapping.LoadDataRow(bool clearDataValues =
false, bool acceptChanges = false) + 0x48 bytes

System.Data.Common.dll!
System.Data.Common.DbDataAdapter.FillLoadDataRow
(System.Data.Common.SchemaMapping mapping =
{System.Data.Common.SchemaMapping}) + 0x50 bytes

System.Data.Common.dll!
System.Data.Common.DbDataAdapter.FillFromReader(System.Object data =
{System.Data.DataTable}, string srcTable = null,
System.Data.IDataReader dataReader =
{System.Data.SqlServerCe.SqlCeDataReader}, int startRecord = 0, int
maxRecords = 0, System.Data.DataColumn parentChapterColumn = <undefined
value>, System.Object parentChapterValue = <undefined value>) + 0x62
bytes

System.Data.Common.dll!System.Data.Common.DbDataAdapter.Fill
(System.Data.DataTable dataTable = {System.Data.DataTable},
System.Data.IDataReader dataReader =
{System.Data.SqlServerCe.SqlCeDataReader}) + 0x3c bytes

System.Data.Common.dll!System.Data.Common.DbDataAdapter.Fill
(System.Object data = {System.Data.DataTable}, int startRecord = 0, int
maxRecords = 0, string srcTable = null, System.Data.IDbCommand command
= {System.Data.SqlServerCe.SqlCeCommand}, System.Data.CommandBehavior
behavior = SingleResult) + 0x4d bytes

System.Data.Common.dll!System.Data.Common.DbDataAdapter.Fill
(System.Data.DataTable dataTable = {System.Data.DataTable},
System.Data.IDbCommand command =
{System.Data.SqlServerCe.SqlCeCommand}, System.Data.CommandBehavior
behavior = SingleResult) + 0x23 bytes

System.Data.Common.dll!System.Data.Common.DbDataAdapter.Fill
(System.Data.DataTable dataTable = {System.Data.DataTable}) + 0x4c
bytes


Now, it seems to me that it's probably a bug in the MS databinding code
anyway, but if we could get rid of the CurrencyManager to start with it
would allow us to work round it. Our current thought is to create a new
DataView for each of the forms, so we can call Dispose on them to
unbind - but that's pretty horrible.

Has anyone else encountered this?
 
J

Jon Skeet [C# MVP]

We are experiencing a simular occurance. Everytime we add the first row to
our datatable, an exception is thown (and internally caught in the framwork).
The row gets added, but it adds a big delay while the exception gets caught.
If we clear the table and repopulate it, the first Add() again causes an
exception, but without the long delay.

If you're running in the debugger, the delay is probably caused by
that. It shouldn't happen in non-debug mode. Exceptions being thrown
and caught within the framework don't bother me too much - it's ones
that "escape" the framework that concern me!
 
J

Jon Skeet [C# MVP]

Actually, I had not tried it "outside" the debugger. Although the exceptions
must still be getting generated, I do not see any slow down on the first row
Add().

Just for completeness:
If I delay binding the datatable to the datagrid until after it has a row of
data, then a) adding the first row does not generate an exception b) no
delay adding the first row c) databinding and showing the data is fast.
If I then delete the rows and re-add one to the now bound grid/table, the
exception now gets thrown and the delay now occurs.
So, the issue is not with the datatable, it is with the databinding to the
grid.

I'm not sure you necessarily *have* an issue - if the exception isn't
propagated to you, then you shouldn't worry about it. The delay may be
slightly annoying in the debugger, but it's not something your
customers will see. You could fake it away by starting a new thread
just to throw and catch an exception on startup, if you wanted.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top