我正在使用相当复杂的GUI,并尝试将大量数据从GUI传递给backgroudWorker。我遇到的问题是从后台工作程序访问一些GUI值。例如,如果我尝试获取ComboBox.Text
,则会因交叉线程而获得InvalidOperationException
。但是,如果我说做TextBox.Text
,一切似乎都可以。当然,我对C#还是比较陌生的,所以我有点不清楚为什么其中一些是好的而另一些是失败的。
我已经提出了几种方法来解决我的问题,但正在寻求从别人谁在C#中所经历的最好的做法。
以下几种方法我可以考虑修复此问题
创建所有你想要传递给后台工作,并通过这个,当你调用RunworkAsync值的类/结构。我没有发现这个非常有吸引力,因为我是有建立在我的GUI为每个页面一个类/结构传递到BackgroundWorker的
创建一组具有特定任务的不同后台工作者。我仍然有一些传递数据的问题,但我必须通过的数据量减少了很多。然而,DoWork的/ ProgressChanged / RunworkerCompleted的数量上升显著这是不太理想的。
(这导致我正在做的事情)
创建一个代理和方法来捕获信息
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越多,项目越复杂,问题就越大。如果有人有任何信息可以使这更容易,我将不胜感激。
由于
答案 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的原因。
我知道可能需要一些额外的前期努力来获得#1或#2,但从长远来看,最终结果会更好。
作为我的回答的推论,当数据需要遵循相反的方向时(从工作线程到UI线程,如在向UI发送进度信息的情况下),Control.Invoke
方法往往被过度使用。遗憾的是,这是BackgroundWorker
内部使用ReportProgress
方法的方法。由于某些与上述相同的原因加上UI线程轮询此信息的共享数据结构,通常通常更好:
但是,据说我不暗示你完全抛弃BackgroundWorker
。请记住这些要点。