Proper way to pass GUI values to backgroundworker?
我正在使用一个相当复杂的 GUI,并试图将大量数据从 GUI 传递到 backgroudWorker。我遇到的问题是从后台工作人员访问一些 GUI 值。例如,如果我尝试获取
我想出了几种方法来解决我的问题,但我正在向有 c# 经验的人寻求最佳实践。
以下是我能想到的解决此问题的几种方法
创建所有要传递给后台工作人员的值的类/结构,并在调用 RunworkAsync 时传递它。我没有发现这很有吸引力,因为我必须为我的 GUI 上的每个页面构建一个类/结构以传递给 backgroundWorker
创建一组具有特定任务的不同后台工作人员。我在传递数据方面仍然存在一些问题,但是我必须传递的数据量被减少了很多。但是,DoWork/ProgressChanged/RunworkerCompleted 的数量显着增加,并不理想。
(这引导我了解我目前正在做的事情)
创建一个委托和方法来捕获信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private delegate string ReadComboDelegate(ComboBox c); private string ReadComboBox(ComboBox c) { if(c.InvokeRequired) { ReadComboDelegate del = new ReadComboDelegate(this.ReadComboBox); return (string) c.Invoke(del,c); } else { return c.Text } } |
然后在
的操作
当您有一个简单的 GUI 并且您不必传递大量数据时,这是一个非常简单的问题。然而,GUI 项目越多、越复杂,这个问题就越大。如果有人有任何信息可以使这更容易,我将不胜感激。
谢谢
您遇到的跨线程问题是由于要求仅允许 UI 线程"触摸"UI 控件。
我认为将数据传递给后台工作人员的最一致的方法是您的解决方案 #1 - 创建一个包含执行处理所需的所有数据的简单结构。
这比为 UI 中的每个控件创建 ReadXXX 方法要简单得多,它定义了后台进程执行其任务所需的内容...
TextBox 不会导致此异常是很偶然的。它的 Text 属性缓存在一个字符串中。对于 ComboBox.Text 和绝大多数其他控件属性而言,情况并非如此,它会询问本机 Windows 控件,此时 Windows 窗体会发现您正在尝试使用来自 UI 线程以外的线程的控件。没办法。
您肯定需要想办法重构这段代码。这不仅是非法的,而且非常昂贵并且从根本上线程不安全,因为 UI 可以在您的工作人员运行时更新。从您需要的控件中收集信息到一个小助手类中,将其作为参数传递给 RunWorkerAsync(object) 重载。并从 e.Argument.
将其取回 DoWork
我肯定会避免#3。尽管人们热衷于使用
- 它将 UI 和工作线程紧密耦合在一起。
- 工作线程可以决定 UI 线程执行多少工作。
- 工作线程必须等待 UI 线程响应才能继续。
- 这是一项昂贵的手术。
我知道您可能需要做一些额外的前期工作才能让 #1 或 #2 顺利进行,但从长远来看,最终结果会更好。
作为我回答的必然结果,当数据也需要遵循相反的方向(从工作线程到 UI 线程,例如向 UI 发送进度信息的情况下)时,
- UI 线程可以决定更新的时间和频率。
- 它将更新 UI 线程的责任放在它应该属于的 UI 线程上。
- 不存在 UI 消息泵溢出的风险,就像工作线程启动的编组技术那样。
但是,话虽如此,我并不是建议您完全放弃