.NET BackGroundWorker - InvalidOperationException : Cross-thread operation not valid
c#, multithreading, winforms
Solution
This is the problem:
label1.Text = i.ToString();
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.
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);
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);
... 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`.
Problem
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. 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) 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. 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, The Layout of my Form: Form - TabControl - Tab1 -Tab1Panel -TextBox1 When reach this line : ``` TextBox txtbox1 = new TextBox(); Tab1Panel.Controls.Add(txtbox1); ``` The error still occur when i add Textbox to Panel Control Programmatically. Finally,I replace by this: ``` if (Tab1Panel.InvokeRequired) Tab1Panel.Invoke((MethodInvoker)delegate { Tab1Panel.Controls.Add(txtbox1); }); else Tab1Panel.Controls.Add(txtbox1); ``` Everything is work. How to determine the control is InvokeRequired, Is it control specified?