我有一个相当复杂的 WinForms 应用程序,它使用数据绑定将强类型的 DataTables 绑定到控件(不确定这个事实在这里是否重要)。当对列的更改触发更新同一行上的另一列的逻辑时会引发异常(或者至少这是我的理论)。
一个示例:客户记录绑定到一个 ComboBox,其中包含 Customer::MarketingContactId 的联系人列表。当联系人更改时,有几个文本框和复选框将更新以允许编辑该联系人的详细信息。其中一个复选框在 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 是正在更新的客户。虽然此代码中不会发生错误,但实际上是由 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 sender, 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 action = {Method = {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 = None, int record2 = 1, System.Data.DataViewRowState oldState2 = None , System.Data.DataViewRowState newState2 = 已添加) 第 3473 行 + 0x18 字节 C# System.Data.dll!System.Data.DataTable.SetNewRecordWorker(System.Data.DataRow row = "CustomerRow: Id:-1", int建议记录,系统.Data.DataRowAction action = Change, bool isInMerge, int position, bool fireEvent = true, out System.Exception deferredException = null) Line 3935 + 0x16 bytes 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) Line 1160 C# System.Data.dll!System.Data.DataRow.EndEdit() Line 631 + 0xa bytes C#
System.Data.dll!System.Data.DataRow.this[System.Data.DataColumn ].set(System.Data.DataColumn 列,对象值) 第 343 行 C#
行号在那里,因为我从 Visual Studio 的 MS 符号服务器功能为 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 逻辑的方法。