【问题标题】:Formatting winforms UI on a background thread在后台线程上格式化 winforms UI
【发布时间】:2012-12-04 11:46:20
【问题描述】:

我有一个表单“StartForm”,用户在其中选择组合框,然后单击一个按钮。从那里我想:

  1. 生成另一个表单的实例,“MainForm”

  2. 在该表单上填充大约 50 000 行的 DataGridView

  3. 遍历数据网格视图中的每一行并对其执行一些处理。就我而言,它根据单元格的值格式化行颜色,并更新一些列。

  4. 显示表单。

这是直截了当的,但是由于大量的行和每一行的处理时间,在构造 MainForm 时 UI 会冻结。因此,我需要在后台线程上构建 MainForm,并在此过程中在 StartForm 上填充进度条。

在使用 backgroundWorker 时,我不断收到跨线程异常或我的格式丢失,并且 control.Invoke() 似乎也抛出异常。也许我只是没有正确使用这些......

有人可以解释一下如何完成上述操作吗?我试图让问题保持基本的理解,以便对其他人有所帮助,但如果您想要我的代码,请询问。

谢谢!

【问题讨论】:

    标签: c# winforms multithreading datagridview


    【解决方案1】:

    我认为您需要为您的数据网格实现虚拟模式。查看有关 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 行数据)。

    【讨论】:

      【解决方案2】:

      默认情况下,所有工作都在 UI 线程上完成,这会产生“崩溃”的错觉,因为在繁重的工作期间 UI 变得无法访问。在不是 UI 线程的线程上创建表单本身是可能的,但这意味着该表单只能由创建它的线程访问,因此这不太可能是您想要的。您收到 cross-thread exception 是因为您尝试从另一个线程修改 UI 线程。

      您可以尝试在后台线程上加载和处理所有数据,但将其加载到新的临时DataTable 中。然后,在 UI 线程上使用 DataSet.Merge(如果您使用的是 BackgroundWorker,可能在 RunWorkerCompleted 事件中)并将临时 DataTable 与绑定到 DataGridView 的主 DataSet 合并。

      这应该意味着所有的处理和繁重的工作都在后台线程上完成,但DataGridView 控件在 UI 线程上更新,从而绕过任何无效的跨线程。附带说明的是,您应该测试DataSet.Merge 的性能。

      【讨论】:

      • 我喜欢这个主意,我会调查一下,谢谢。但处理和格式化是在 DataGridView 本身上完成的(即更改特定行的背景颜色)。
      • 关于颜色格式方面,这里的答案可能会有所帮助stackoverflow.com/questions/1630066/…
      猜你喜欢
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      相关资源
      最近更新 更多