データ バインディングを使用して厳密に型指定された DataTable をコントロールに結び付ける、かなり複雑な WinForms アプリがあります (この事実がここで重要かどうかはわかりません)。列への変更によって、同じ行の別の列を更新するロジックがトリガーされると、例外が発生します (少なくともこれは私の理論です)。
例: Customer レコードは、Customer::MarketingContactId への連絡先のリストを含む ComboBox にバインドされます。連絡先が変更されると、その連絡先の詳細を編集できるように更新されるいくつかのテキストボックスとチェックボックスがあります。これらのチェックボックスの 1 つには、CheckChanged のイベント ハンドラーがあります。
void MarketingContactIsFulltimeChangedHandler(object sender, EventArgs e)
{
var contact = m_row.MarketingContact;
if (contact != null && contact.IsFullTimeEmployee)
{
var i = m_row.Institution;
if (i.CreditLevel > m_row.CreditLevel)
m_row.CreditLevel = i.CreditLevel;
}
}
m_row は更新される Customer です。ただし、このコードではエラーは発生しませんが、実際には MarketingContactId フィールドの設定から発生します。これを確認するコール スタックを次に示します。
System.Data.dll!System.Data.DataView.OnListChanged(System.ComponentModel.ListChangedEventArgs e = {System.ComponentModel.ListChangedEventArgs}) 行 1433 + 0x2c バイト C# System.Data.dll!System.Data.DataView.IndexListChanged(object送信者、System.ComponentModel.ListChangedEventArgs e = {System.ComponentModel.ListChangedEventArgs}) 1299 行 C# System.Data.dll!System.Data.DataView.IndexListChangedInternal(System.ComponentModel.ListChangedEventArgs e) 1324 行 C#
System.Data.dll! System.Data.DataViewListener.IndexListChanged(System.ComponentModel.ListChangedEventArgs e) 行 76 + 0x7 バイト C#
System.Data.dll!System.Data.Index.OnListChanged.AnonymousMethod(System.Data.DataViewListener listener, System.ComponentModel.ListChangedEventArgs args 、bool arg2、bool arg3) 803 行目 + 0x7 バイト C#
System.Data.dll!System.Data.Listeners.Notify(System.ComponentModel.ListChangedEventArgs arg1 = {System.ComponentModel.ListChangedEventArgs}、bool arg2 = false、bool arg3 = false、System.Data.Listeners.Action アクション = {メソッド= {Void b__2(System.Data.DataViewListener, System.ComponentModel.ListChangedEventArgs, Boolean, Boolean)}}) 1029 行目 + 0x1a バイト C# System.Data.dll!System.Data.Index.OnListChanged(System.ComponentModel.ListChangedEventArgs e ) 行 805 C# System.Data.dll!System.Data.Index.OnListChanged(System.ComponentModel.ListChangedType changedType, int newIndex, int oldIndex) 行 788 C# System.Data.dll!System.Data.Index.RecordStateChanged(int oldRecord 、System.Data.DataViewRowState oldOldState、System.Data.DataViewRowState oldNewState、int newRecord、System.Data.DataViewRowState newOldState、System.Data.DataViewRowState newNewState) 903 行目 + 0x10 バイト C#
System.Data.dll!System.Data.DataTable.RecordStateChanged(int record1 = 0、System.Data.DataViewRowState oldState1 = 追加、System.Data.DataViewRowState newState1 = なし、int record2 = 1、System.Data.DataViewRowState oldState2 = なし, System.Data.DataViewRowState newState2 = 追加) 行 3473 + 0x18 バイト C# System.Data.dll!System.Data.DataTable.SetNewRecordWorker(System.Data.DataRow 行 = "CustomerRow: Id:-1", int proposalRecord, System .Data.DataRowAction アクション = 変更、bool isInMerge、int 位置、bool fireEvent = true、out System.Exception deferredException = null) 行 3935 + 0x16 バイト C#
System.Data.dll!System.Data.DataTable.SetNewRecord(System.Data.DataRow 行、int 提案レコード、System.Data.DataRowAction アクション、bool isInMerge、bool fireEvent) 行 3824 C# System.Data.dll!System.Data. DataRow.SetNewRecord(int record) 行 1160 C# System.Data.dll!System.Data.DataRow.EndEdit() 行 631 + 0xa バイト C#
System.Data.dll!System.Data.DataRow.this[System.Data.DataColumn ].set(System.Data.DataColumn column, object value) 行 343 C#
Visual Studio の MS Symbol Server 機能から System.Data.dll のシンボルをロードしたため、行番号が表示されます。このデータがあれば、OnListChanged メソッドのこの部分でエラーをさらに追跡できます。
// snippet from System.Data.DataView::OnListChanged(ListChangedEventArgs e)
if (onListChanged != null) {
if ((col != null) && (e.NewIndex == e.OldIndex)) {
ListChangedEventArgs newEventArg = new ListChangedEventArgs(e.ListChangedType, e.NewIndex, new DataColumnPropertyDescriptor(col));
/*Here is where VS breaks for the exception*/ onListChanged(this, newEventArg);
} else {
onListChanged(this, e);
}
}
onListChanged != null のチェックの直後であれば、明らかに何かが間違っています。私の疑いは、EndEdit メソッド中に DataRow を更新すると、これがトリガーされるということです。もちろん、この問題を切り分けるための単純なサンドボックスでは、エラーは再現されませんでした。SO の他の誰かがこのバグに遭遇しましたか? もしそうなら、どのように修正しましたか?
今のところ私の手間は、MarketingContactIsFulltimeChangedHandler の BeginInvoke を呼び出して、そこで CreditLevel ロジックを実行する別のメソッドにすることです。