BackgroundWorker – 跨线程操作无效

我有一个winform应用程序(一个表单),在这个表单上有一个RichTextBox。 在这个窗体的构造函数中,我创建了一个MyClass类的实例。 在“Form_Load”中,我从MyClass实例调用Initialisation方法。

在表单构造函数中

 myClass = new MyClass(RichTextBox richTextBox); 

在Form_Load中

 myClass.Initialisation(); 

Initialisation方法中,在循环中,我读了一些参数做其他的东西。 要不冻结应用程序(因为某些操作可能需要一段时间,几秒钟),我使用BackgroundWorker 。 我这样使用它(见下面的代码)。

当我执行时,我收到此错误: 跨线程操作无效:控制’richTextBox’从其创建的线程以外的线程访问

你能告诉我怎么解决这个问题吗? 当我不访问richTextBox时,工作完美

 public Class MyClass { static BackgroundWorker _bw; public MyClass() { _bw = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; _bw.DoWork += bw_DoWork; _bw.ProgressChanged += bw_ProgressChanged; _bw.RunWorkerCompleted += bw_RunWorkerCompleted; } static void bw_DoWork(object sender, DoWorkEventArgs e) { foreach (....) { if (....) { richtextBox.Text.AppendText("MyText"); } } e.Result = true; } static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){} static void bw_ProgressChanged(object sender, ProgressChangedEventArgs e){} } 

使用BackgroundWorker不会免除正常的线程规则 – 例如只有 UI线程才能访问UI组件。

如果要从BackgroundWorker更新UI而不是使用进度/完成事件(在UI线程上引发),则需要像在其他情况下一样使用Control.Invoke / Control.BeginInvoke 。 例如:

 if (....) { Action action = () => richtextBox.Text.Add("MyText"); richtextBox.Invoke(action); // Or use BeginInvoke } 

试试这段代码,

 BeginInvoke((MethodInvoker)delegate { richtextBox.Text.Add("MyText"); }); 

使用BackgroundWorker组件,只有ProgressChangedRunWorkerCompleted事件允许您调用UI控件上的方法/属性(应始终在UI线程上完成)。 当您在非UI线程上运行的DoWork事件中更新UI时,您会收到此错误,如果您愿意,您应该使用DoWork事件中的Invoke或BeginInvoke方法更新UI控件。

为了使它更干净并且基于Jon Skeet的建议,我做了一个扩展方法,它做同样的事情,你可以将“ this Label control ”更改为this TextBox control或简单地使用“ this Control control ”(并且基本上允许每个控件都是轻松更新):

 internal static class ExtensionMethods { ///  /// Updates the label text while being used in a multithread app. ///  /// The control. /// The text. internal static void UpdateThreadedText(this Label control, string text) { Action action = () => control.Text = text; control.Invoke(action); } ///  /// Refreshes the threaded. ///  /// The control. internal static void RefreshThreaded(this Label control) { Action action = control.Refresh; control.Invoke(action); } } 

然后使用非常简单:

 this.yourLabelName.UpdateThreadedText("This is the text"); this.yourTextBoxName.UpdateThreadedText("This is the text"); this.yourControlName.UpdateThreadedText("This is the text"); 

要么

 this.yourLabelName.RefreshThreaded(); 

很适合我:)

我认为错误在这一行停止:

 richtextBox.Text.Add("MyText"); 

你的问题我跟这个类似:

BackgroundWorker OnWorkCompleted抛出跨线程exception

加:

 e.Result = "MyText"; 

在你的bw_DoWork

 richTextBox1.AppendText((string)e.Result); 

在你的bw_RunWorkerCompleted

(改变它以适合您的代码)

编辑:

如果在BackgroundWorker工作期间多次完成,您可以添加:

 _bw.ReportProgress(0, "MyText"); 

bw_DoWork并:

 richTextBox1.AppendText((string)e.UserState); 

bw_ProgressChanged

你也可以试试这个。

 this.Invoke(new MethodInvoker(delegate() { richtextBox.Text.Add("MyText"); }));