我有一个相当复杂的WinForms应用程序,它使用数据绑定将强类型DataTable绑定到控件(不确定这个事实是否在这里很重要)。当对列的更改触发更新同一行上的另一列(或至少这是我的理论)的逻辑时,会引发异常。
示例:客户记录绑定到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)}})Line 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 proposedRecord, System.Data.DataRowAction action = Change,bool isInMerge,int position,bool fireEvent = true,out System.Exception deferredException = null)行3935 + 0x16字节C#
System.Data.dll中!System.Data.DataTable.SetNewRecord(的System.Data.DataRow row,int proposedRecord,System.Data.DataRowAction action,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 列,对象值)第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会触发这一点。当然,一个简单的沙箱来隔离这个问题并没有为我重新定义错误。有没有其他人遇到这个bug,如果是这样,你是如何解决它的?
我现在的kludge是将MarketingContactIsFulltimeChangedHandler中的BeginInvoke调用到另一个在那里执行CreditLevel逻辑的方法。