[英]Uncatchable exception in DataGridView when deleting rows in datatable
我有一个数据表,其中根据互联网上可用的数据添加行。 每次添加一行时,我都会在该行上添加一个时间戳。 这已经工作了很多年,数百名用户都没有发生任何错误。 现在,我希望根据数据的使用期限从数据表中删除行。 我有一个计时器,它会触发每个用户定义的时间间隔,然后搜索所有较旧的行并将其删除。 问题是,我收到的各种错误似乎都在改变,即使我在所有方法上都尝试了catch语句,也未捕获到错误。 仅在program.cs中整个应用程序的错误捕获中捕获该错误,这些错误是“退出错误:未将对象引用设置为对象的实例。在System.Windows.Forms.DataGridViewCell.PaintWork,或退出错误:索引超出范围,必须为非负数且小于集合的大小参数名称:System.Collections.ArrayList.get_Item(Int32 index)处的索引
或退出错误:对象引用未设置为对象的实例。 在System.Windows.Forms.DataGridViewTextBoxCell.PaintPrivate
但是其余的错误中没有有用的信息。 这是代码:
public void ageTimer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
try
{
spotAge = Convert.ToDouble(Properties.Settings.Default.SpotAge);
//Select all rows in datatable where the age is older than spotAge and delete them.
//date is stored in dt as 20:12:2017: 21:49:02 derived from DateTime.UtcNow.ToString("dd:MM:yyyy: HH:mm:ss")
//spotTime is the time from the table
DateTime spotTime;
dt.AcceptChanges();
var rowCount = dt.Rows.Count;
for (int i = rowCount -1; i >= 0; i--)
{
DataRow dr = dt.Rows[i];
spotTime = DateTime.ParseExact(Convert.ToString(dr["date"]), "dd:MM:yyyy: HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
if (spotTime.AddMinutes(spotAge) <= DateTime.UtcNow)
{
dr.Delete();
}
}
dt.AcceptChanges();
dataGridView1.Update();
dataGridView1.Refresh();
dataGridView1.FirstDisplayedScrollingRowIndex = 0;
}
catch (Exception x)
{
}
}
现在有趣的是,在我的系统上这根本不会崩溃。 但是,如果我在调试模式下运行Visual Studio,它将可以。 它还会在少数用户上崩溃。 但不是所有人。
我尝试了相同的代码,除了我总是会只删除一行并且它工作得很好。 我尝试删除除第一行,前两行之外的所有行,但仍然崩溃。
根据下面的评论指出计时器在单独的线程上运行,我添加了以下内容:
public void ageTimer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
DeleteRows("");
}
上面的代码现在具有以下内容:
private void DeleteRows(string details)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(DeleteRows), new object[] { details});
return;
}
其余代码如上。 这样可以彻底解决问题。 非常感谢!
请再次阅读您的问题。 这已经工作了好几年了。 现在它不起作用,因为您添加了计时器,并在新的单独线程中运行。 这可能是比赛条件。 显然,dt是一种共享资源,在多线程环境中不能正确使用。 假设dt
是数据网格视图的源,在一种情况下,用户可能正在使用它(只需滚动就足以从dt中读取内容,以便绘制新的可见行-因此,我想您会从那里得到PaintWork错误,因为状态在平均时间内被计时器事件处理程序更改了)。 想象一下,用户从网格中删除了行,这反映了基础源dt
,但是,您的计时器刚好在刚才删除了这些行,并且您获得了索引超出范围的异常。
除了可以在计时器事件处理程序中使用dt
,还可以尝试制作它的副本dt_copy
(只是注意不要制作浅表副本)。 进行更改,完成后,只需将该副本绑定为新的datagridview源即可,一切都会很好。
另一种可能执行起来也更快的方法是调用存储过程并直接由数据库删除,并在调用返回后立即刷新dt
(只需重新填充dt
)。
在这两种情况下,取决于删除的速度,您应该检查'dt'是否脏(同时由用户更新),并且可能希望合并这些更改,以免丢失。
这里的问题是,您要在for循环中调用delete row.delete语句。 这是在操纵行集合的长度,从而使索引超出绑定异常范围。
来自msdn的一句话:
遍历DataRowCollection对象时,不应在foreach循环中调用Delete。 删除修改集合的状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.