.NET的BackgroundWorker - InvalidOperationException异常:跨线程操作无效 [英] .NET BackGroundWorker - InvalidOperationException : Cross-thread operation not valid
问题描述
我有一个项目在.NET的WinForms编码。
我需要实现数据挖掘操作,打印文本到文本框和更新进度。
I have a project coded in .NET Winforms. I need to implement a data-mining operation, print the text to TextBox and update the progress.
我试图用BackgroundWorker的做的,但它抛出一个InvalidOperationException异常(跨线程操作无效:从比其他线程控制XXXXX访问跟帖它是在创建)
I tried to use BackgroundWorker to do, but it throws a InvalidOperationException (Cross-thread operation not valid: Control ‘xxxxx’ accessed from a thread other than the thread it was created on)
要缩小问题的潜在原因,我开始一个新项目,包括以下内容:
键 - 要启动的BackgroundWorker
标签 - 打印文本。
和进度
To narrow down the potential causes of the problem, I started a new project, included the following: Button - To start the BackgroundWorker Label - to print the text. And ProgressBar.
但是,结果是一样的。我搜索了SOF,被告知要使用委托,但我不熟悉它
However, the result is the same. I searched on SOF, and was told to use a delegate, but I am not familiar with it.
这是引发错误的代码示例:
This is the code sample that throws the error:
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace TestProject
{
public partial class Form1 : Form
{
private readonly BackgroundWorker _bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
_bw.DoWork += RosterWork;
_bw.ProgressChanged += BwProgressChanged;
_bw.RunWorkerCompleted += BwRunWorkerCompleted;
_bw.WorkerReportsProgress = true;
_bw.WorkerSupportsCancellation = false;
}
private void RosterWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
for (int i = 0; i < 1000; i++)
{
label1.Text = i.ToString();
_bw.ReportProgress(Convert.ToInt32((i * (100 / 1000))));
}
}
private void BwProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void btnStart_Click(object sender, EventArgs e)
{
progressBar1.Show();
_bw.RunWorkerAsync();
}
private void BwRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Hide();
}
}
}
更新:
我跟乔恩飞碟双向的答案,它真的在我的测试项目工作,但回到我真正的项目,
Update: I follow Jon Skeet's answer, it really work on my test project, but back to my real project,
的布局我的方式:
表 -
的TabControl
- TAB1
-Tab1Panel
-TextBox1
Form - TabControl - Tab1 -Tab1Panel -TextBox1
在到达这一行:
TextBox txtbox1 = new TextBox();
Tab1Panel.Controls.Add(txtbox1);
错误仍然当我添加文本框面板控制编程发生。
The error still occur when i add Textbox to Panel Control Programmatically.
最后,我取代的:
if (Tab1Panel.InvokeRequired)
Tab1Panel.Invoke((MethodInvoker)delegate { Tab1Panel.Controls.Add(txtbox1); });
else
Tab1Panel.Controls.Add(txtbox1);
一切工作。 ?如何确定控制InvokeRequired,难道是控制中指定
Everything is work. How to determine the control is InvokeRequired, Is it control specified?
推荐答案
这就是问题所在:
label1.Text = i.ToString();
您正试图改变在的BackgroundWorker $标签文本C $ C>,这是不是在UI线程上运行。点
的BackgroundWorker
是做所有非UI那里工作,使用 ReportProgress
定期回头来UI线程,并更新你所取得的进步的用户界面。
You're trying to change the label text within the BackgroundWorker
, which is not running on a UI thread. The point of BackgroundWorker
is to do all the non-UI work there, using ReportProgress
to periodically "go back" to the UI thread and update the UI with the progress you're making.
所以的或者的您需要更改 LABEL1的.text
在 BwProgressChanged
以及或的,你需要使用 Control.Invoke
/ 的BeginInvoke
就像你从任何其他后台线程:
So either you need to change label1.Text
in BwProgressChanged
as well, or you need to use Control.Invoke
/BeginInvoke
just as you would from any other background thread:
// Don't capture a loop variable in a lambda expression...
int copy = i;
Action updateLabel = () => label1.Text = copy.ToString();
label1.BeginInvoke(updateLabel);
有关更多关于复制的一部分,看到埃里克利珀的博客文章,的\"Closing在循环变量有害。在这种特殊情况下,这只是一个问题,因为我使用的BeginInvoke
。这的可能的改变只是:
For more about the copying part, see Eric Lippert's blog post, "Closing over the loop variable considered harmful". In this particular case it's only an issue because I'm using BeginInvoke
. This could be changed to just:
Action updateLabel = () => label1.Text = i.ToString();
label1.Invoke(updateLabel);
...但现在的背景工人将永远等待UI赶上它一直前去,这在现实生活中的一般的不是你想要的。我一般喜欢的BeginInvoke
在调用
。
... but now the background worker would always be waiting for the UI to catch up before it kept going, which in real life is usually not what you want. I generally prefer BeginInvoke
over Invoke
.
这篇关于.NET的BackgroundWorker - InvalidOperationException异常:跨线程操作无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!