将GUI值传递给后台工作者的正确方法?

时间:2010-10-22 20:20:23

标签: c# multithreading user-interface backgroundworker

我正在使用相当复杂的GUI,并尝试将大量数据从GUI传递给backgroudWorker。我遇到的问题是从后台工作程序访问一些GUI值。例如,如果我尝试获取ComboBox.Text,则会因交叉线程而获得InvalidOperationException。但是,如果我说做TextBox.Text,一切似乎都可以。当然,我对C#还是比较陌生的,所以我有点不清楚为什么其中一些是好的而另一些是失败的。

我已经提出了几种方法来解决我的问题,但正在寻求从别人谁在C#中所经历的最好的做法。

以下几种方法我可以考虑修复此问题

  1. 创建所有你想要传递给后台工作,并通过这个,当你调用RunworkAsync值的类/结构。我没有发现这个非常有吸引力,因为我是有建立在我的GUI为每个页面一个类/结构传递到BackgroundWorker的

  2. 创建一组具有特定任务的不同后台工作者。我仍然有一些传递数据的问题,但我必须通过的数据量减少了很多。然而,DoWork的/ ProgressChanged / RunworkerCompleted的数量上升显著这是不太理想的。

  3. (这导致我正在做的事情)

  4. 创建一个代理和方法来捕获信息

    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
        }
    }
    

    然后在DoWork内,做string txt = this.ReadComboBox(this.comboBox1);

    之类的事情

    当你有一个简单的GUI并且你不必传递大量数据时,这是一个非常简单的问题。但是,GUI越多,项目越复杂,问题就越大。如果有人有任何信息可以使这更容易,我将不胜感激。

    由于

3 个答案:

答案 0 :(得分:2)

您遇到的跨线程问题是由于要求只允许UI线程“触摸”UI控件。

我认为最常见的将数据传递给后台工作者的方法是您的解决方案#1 - 创建一个包含执行处理所需的所有数据的简单结构。

这比为UI中的每个控件创建ReadXXX方法简单得多,它定义了后台进程执行任务所需的内容......

答案 1 :(得分:1)

TextBox不会导致此异常,这是偶然的。它的Text属性缓存在一个字符串中。这不是ComboBox.Text和绝大多数其他控件属性的情况,它询问本机Windows控件,此时Windows Forms发现您正在尝试使用来自UI线程以外的线程的控件。不行。

您肯定需要考虑重构此代码的方法。它不仅非法,而且非常昂贵并且从根本上说是不安全的,因为在您的工作人员运行时可以更新UI。将您需要的控件中的信息收集到一个小帮助器类中,将其作为参数传递给RunWorkerAsync(对象)重载。并从e.Argument中将其恢复到DoWork中。

答案 2 :(得分:0)

我绝对会避免#3。尽管使用Control.Invoke来协调工作线程和UI线程的热情,但它经常被过度使用,并且通常是最佳的次优策略。我更喜欢#1和#2而不是#3。以下是我倾向于避免#3的原因。

  • 它紧密结合了UI和工作线程。
  • 工作线程决定UI线程执行的工作量。
  • 工作线程必须等待UI线程响应才能继续。
  • 这是一项昂贵的操作。

我知道可能需要一些额外的前期努力来获得#1或#2,但从长远来看,最终结果会更好。

作为我的回答的推论,当数据需要遵循相反的方向时(从工作线程到UI线程,如在向UI发送进度信息的情况下),Control.Invoke方法往往被过度使用。遗憾的是,这是BackgroundWorker内部使用ReportProgress方法的方法。由于某些与上述相同的原因加上UI线程轮询此信息的共享数据结构,通常通常更好:

  • UI线程决定更新的发生时间和频率。
  • 它将更新UI线程的责任放在它应该属于的UI线程上。
  • UI消息泵没有溢出的风险,就像工作线程启动的编组技术一样。

但是,据说我暗示你完全抛弃BackgroundWorker。请记住这些要点。