我创建了一个winform应用, 应用里有DataGridView,用BindingList做数据源.
MotionList = new List<Motion>();
MotionBList = new BindingList<Motion>(MotionList);
DataGridViewMotion.DataSource = MotionBList;
DataGridViewMotion.RowHeadersVisible = false;
DataGridViewMotion.AllowUserToAddRows = false;
DataGridViewMotion.ReadOnly = true;
Motion的定义如下
public class Motion
{
public string StartPos { get; set; }
public string EndPos { get; set; }
}
我用 MotionBList.Add()
MotionBList.RemoveAt()
这两方法来更新DataGridViewMotion。 大部分时候都没问题,都正常。有几条线程更新MotionBList,但是都用的是SyncContext在UI线程上执行。
SyncContext = WindowsFormsSynchronizationContext.Current;
SyncContext.Post(new SendOrPostCallback((_) =>
{
if (MotionBList.Count > 600)
{
for (int i = 0; i < 100; i++)
{
MotionBList.RemoveAt(0);
}
}
MotionBList.Add(MakeMotion(...));
}), null);
private Motion MakeMotion(string a, string b)
{
return new Motion() {StartPos = a, EndPos = b};
}
但是有很小的概率,在用 MotionBList.Add(new Motion(...))
时会报异常, 异常的信息如下:
Application_ThreadException System.ArgumentOutOfRangeException:107 的值对于 indexStart 无效, indexStart 必须小于或等于 93.
Application_ThreadException System.ArgumentOutOfRangeException: 1270 的值对于 indexStart 无效, indexStart 必须小于或等于 598.
在 System.Windows.Forms.DataGridViewRowCollection.GetPreviousRow(Int32 indexStart, DataGridViewElementStates includeFilter)
在 System.Windows.Forms.DataGridViewRowCollection.GetPreviousRow(Int32 indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
在 System.Windows.Forms.DataGridView.CorrectRowFrozenState(DataGridViewRow dataGridViewRow, DataGridViewElementStates rowState, Index32 anticiptedRowIndex)
在 System.Windows.Forms.DataGridView.OnInsertingRow(Int32 rowIndexInserted, DataGridViewRow dataGridViewRow, DataGridViewElementStates rowState, Point& newCurrentCell, Boolean firstInsertion, Int32 insertionCount, Boolean force)
在 System.Windows.Forms.DataGridViewRowCollection.InsertInternal(Int32 rowIndex, DataGridViewRow dataGridViewRow, Boolean force)
在 System.Windows.Forms.DataGridViewRowDataCollection.ProcessListChanged(ListChangedEventArgs e)
在 System.Windows.Forms.DataGridViewRowDataCollection.currencyManager_ListChanged(Object sender, ListChangedEventArgs e)
在 System.Windows.Forms.CurrencyManager.OnListChanged(ListChangedEventArgs e)
在 System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
在 System.ComponentModel.BindingList'1.OnListChanged(ListChangedEventArgs e)
在 System.ComponentModel.BindingList'1.FireListChanged(ListChangedType type, Int32 index)
在 System.ComponentModel.BindingList'1.InsertItem(Int32 index, T item)
在 System.Collections.ObjectModel.Collection'1.Add(T item)
在 MotionBList.Add(MakeMotion(...))
然后其他很多控件上就出现红叉叉, 上面的异常信息是Programe.cs里的代码捕获到的
Application.ThreadException += Application_ThreadException;
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show($"Application_ThreadException {e.Exception}");
}
异常信息的MessageBox,图里报出错误的825那一行,就是一句 MotionBList.Add(MakeMotion(...))
Application_ThreadException System.ArgumentOutOfRangeException: The
107 的值对于 indexStart 无效, indexStart 必须小于或等于 93.
Application_ThreadException
System.ArgumentOutOfRangeException: 1270 的值对于
indexStart 无效, indexStart 必须小于或等于 598.
你的这个错误信息,怎么看到是多线程操作,出现的问题,多线程访问同一个数据,并进行修改,造成了线程不安全