2

有没有办法将一组结果(例如 DataTable)从 BackgroundWorker“流式传输”到 DataGridView。我想要做的是查询数据,并将结果填充到 DataGridView(如 SQL Server Management Studio 中的查询网格结果)。我的第一个想法是使用 BackgroundWorker(以避免 UI 冻结效果),但是当 BackgroundWorker 正在加载结果时,仍然会有一个可感知的“滞后”。

解决此问题的最佳方法是什么?

4

4 回答 4

1

你可以:

将 DataGridView 绑定到最初为空的 DataTable。

然后,在您的工作线程中,使用线程安全集合(例如同步队列)并调用 Control.BeginInvoke 将记录信息传递给 UI 线程。

在 UI 线程中,您将从队列中拉出项目并将相应的行添加到 DataTable。通过数据绑定的魔力,这些将被添加到网格视图中。

但是,通过使用多线程,您会立即使您的程序更容易被破坏!我还没有尝试过这个特定的方案,并且不知道在将项目添加到 GridView 时是否会有效地使其无法使用。我已经使用多线程填充了一个树视图,这确实是一个很酷的效果。但是,我最终禁用了该功能,因为它引入了错误,因为它不是一个完全正确的实现来处理所有可能的用户交互。

于 2008-11-02T22:35:44.543 回答
1

已经尝试过了,并且做到了这一点。应用程序和架构是在我来公司之前完成的,我所做的就是让它“分页”和异步。

他们有一个已经有分页的存储过程......所以我所做的是,在第一次请求时,发回总结果的“大小”(以及 page1 的数据)。

在客户端,我将空白行添加到 DataTable...(空白,“RowNumber”字段除外)

在进一步的数据页面(异步接收)上,我会得到 rows[X],将它的“ItemArray”设置为新数组,然后更新我的网格。例子:

myDataGridView.Rows[rowNumber].SetValues(valuesFromNewPage);
于 2008-11-02T23:13:39.397 回答
1

如果您只有一个可以修改底层集合的线程,这会更好。我有一个只读 DGV,因此添加/删除行的唯一方法是操作底层 BindingSource。我有一个同步线程,它定期从 BindingSource 添加/删除项目。

我确实必须做一件“棘手”的事情——如果要更新的项目是选定的项目,你不能只说

myBindingSource[n] = newItem;

而是您必须将新项目中的值深度复制到现有项目中。否则,您将触发“已更改”事件,该事件将重绘绑定到您的数据源的任何其他内容。当我做参考副本时,我得到了一个明显的闪烁,切换到深拷贝(仅适用于当前项目)修复了它。

当然,如果您让用户直接从表单中修改数据,而不是将其用作只读视图,那么您将打开一个全新的(丑陋的!)蠕虫罐。

于 2009-01-08T22:13:27.207 回答
0

如果该过程需要 2 秒或更短的时间,那么我会显示一个“忙碌”光标并进行内联更新。这有两个原因:

  • 开始只需几秒钟的操作的人在操作完成时仍将处于“集中”思维模式。潜意识里,他仍在等待行动的结果,还没有将他的有意识的大脑从那个特定的焦点上转移出来(只要应用程序显示“忙碌”信号)。

  • 鉴于上述情况,我不认为多线程的认知开销以及随之而来的危险是值得承担的。

如果该过程最多需要 5 秒,那么我会首先集中精力将其减少到 2 秒或更短。同样,专注于提高性能(例如,通过在 SQL 中分页)通常比引入多线程要容易得多。即使使用BackgroundWorker类型,多线程中涉及的非顺序交互仍然难以分析和确保安全。

如果您发现无法将延迟减少到 2 秒或更短,那么您可以采用类似 confuzatron 推荐的技术。但即便如此,您可能仍希望向最终用户显示进度对话框,因为他在等待超过 2 秒后进行上下文切换。进度对话框为他提供了易于吸收的信息,说明他何时可以切换回专注于您的上下文。

于 2008-11-03T14:59:04.107 回答