我有一个表单“StartForm”,用户在其中选择一个组合框,然后单击一个按钮。从那里我想:
生成另一个表单的实例“MainForm”
在该表单上填充大约50 000行的DataGridView
循环遍历数据网格视图中的每一行并对其执行一些处理。在我的例子中,它根据单元格的值格式化行颜色,并更新一些列。
显示表单。
这是直截了当的,但是由于每行的行数和处理时间都很多,因此在构造MainForm时UI会冻结。因此,我需要在后台线程上构建MainForm,并在进行此操作时使用进度条来填充StartForm。
我在使用backgroundWorker时仍然遇到跨线程异常或我的格式丢失,而control.Invoke()似乎也会抛出异常。也许我只是没有正确使用这些......
有人可以解释一下如何完成上述工作吗?我试图让问题基本理解,以便它对其他人有所帮助,但如果您想要我的代码,请询问。
谢谢!
答案 0 :(得分:2)
我认为您需要为数据网格实施虚拟模式。看看关于implementing Virtual Mode in the DataGridView Control的msdn文章。小样本:
grid.VirtualMode = true; // enable virtual mode
grid.RowCount = source.Count; // 50000
grid.CellValueNeeded += grid_CellValueNeeded;
grid.CellPainting += grid_CellPainting;
使用CellValueNeeded
事件处理程序为单元格提供值(即从源中选择值)。使用CellPainting
事件处理程序根据单元格值设置单元格颜色(使用e.CellStyle
属性)。如果用数据填充源需要很长时间,则可以在BackgroundWorker中执行此操作。但是在虚拟模式下格式化和显示数据 - 这是最好的选择,当你有大量的行时(顺便说一下,考虑应用一些过滤 - 很少用户一次需要50000行数据)。
答案 1 :(得分:0)
默认情况下,所有工作都在UI线程上完成,这会产生“崩溃”的错觉,因为在繁重的工作期间UI变得无法访问。在不是UI线程的线程上创建表单本身是可能的,但这意味着表单只能由创建它的线程访问,所以它不太可能是你想要的。您正在获取cross-thread exception
,因为您正在尝试从另一个线程修改UI线程。
您可以尝试加载和处理后台线程上的所有数据,但将其加载到新的临时DataTable
中。然后,在UI线程上使用DataSet.Merge(如果您正在使用BackgroundWorker,可能在RunWorkerCompleted
事件中)并将临时DataTable与绑定到DataGridView的主DataSet合并。
这应该意味着所有处理和繁重的工作都在后台线程上完成,但DataGridView
控件在UI线程上更新,从而绕过任何无效的交叉线程。另一方面,您应该测试DataSet.Merge
的性能。