.NET BackGroundWorker - InvalidOperationException: Cross-thread operation not valid

I have a project encoded in .NET Winforms. I need to implement a data mining operation, print the text in a TextBox and update the progress.

I tried using BackgroundWorker, but it throws an InvalidOperationException ( Invalid cross-stream operation: Control 'xxxxx accessed from a stream other than the stream that was created on )

To narrow down the potential causes of the problem, I started a new project by including the following in it: Button - launch BackgroundWorker Shortcut - to print text. And the ProgressBar.

However, the result is the same. I searched in SOF and I was told to use a delegate, but I am not familiar with it.

This is an example of the code that causes 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 John Skeet's answer, he is really working on my test project, but is returning to my real project,

Layout of my form:

Form - TabControl - Tab1 -Tab1Panel -TextBox1

Upon reaching this line:

 TextBox txtbox1 = new TextBox(); Tab1Panel.Controls.Add(txtbox1); 

The error still occurs when I add a text box to the control panel programmatically.

Finally, I will replace with this:

  if (Tab1Panel.InvokeRequired) Tab1Panel.Invoke((MethodInvoker)delegate { Tab1Panel.Controls.Add(txtbox1); }); else Tab1Panel.Controls.Add(txtbox1); 

Everything works. How to detect an InvokeRequired control, is this control set?

+4
source share
4 answers

This is the problem:

 label1.Text = i.ToString(); 

You are trying to change the label text inside BackgroundWorker , which does not work in the user interface thread. The point of BackgroundWorker is to do all the non-UI work there, using ReportProgress , to periodically โ€œreturnโ€ to the user interface thread and update the user interface with the success you are doing.

So, either you need to change label1.Text in BwProgressChanged , or you need to use Control.Invoke / BeginInvoke in the same way as in 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 information on the copy part, see Eric Lippert's blog post, "Closing a loop variable that is considered harmful . " In this particular case, this is only a problem, because I use BeginInvoke . This can be changed like this:

 Action updateLabel = () => label1.Text = i.ToString(); label1.Invoke(updateLabel); 

... but now the background worker will always wait for the user interface to catch up before it keeps going, which in real life is usually not what you want. I usually prefer BeginInvoke over Invoke .

+11
source

use this code iw will work

  BeginInvoke((MethodInvoker)delegate { TextBox1.Text += "your text here"; }); 
+3
source

You get access to your tag - which was created in the GUI thread - from inside your working folder. Access to the Windows control from a thread other than the one on which the control was created is not allowed; therefore you are granted an exception.

You should not access the label directly, but instead you should raise the event from your stream, and make sure that it is called in the correct stream - which signals the interface so that you can change the contents of the label.

0
source

You must execute control methods from the thread that created them. To update them from another thread, use Invoke . An example of how this can be done can be found here . You should also read Threading with Forms and Controls on MSDN.

0
source

Source: https://habr.com/ru/post/1379082/


All Articles