Csharp/C#教程:.NET BackGroundWorker – InvalidOperationException:跨线程操作无效分享


.NET BackGroundWorker – InvalidOperationException:跨线程操作无效

我有一个用.NET Winforms编码的项目。 我需要实现数据挖掘操​​作,将文本打印到TextBox并更新进度。

我尝试使用BackgroundWorker来做,但是它抛出了一个InvalidOperationException( 跨线程操作无效:控件’xxxxx’从其创建的线程以外的线程访问

为了缩小问题的潜在原因,我开始了一个新项目,包括以下内容:按钮 – 启动BackgroundWorker标签 – 打印文本。 和ProgressBar。

但是,结果是一样的。 我搜索了SOF,并被告知要使用代表,但我不熟悉它。

这是抛出错误的代码示例:

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(); } } } 

更新:我遵循Jon Skeet的回答,它确实适用于我的测试项目,但回到我的真实项目,

我的表格布局:

表单 – TabControl – Tab1 -Tab1Panel –TextBox1

到达此行时:

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

当我以编程方式将Textbox添加到Panel Control时,仍会出现错误。

最后,我替换为:

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

一切都是有效的。 如何确定控件是InvokeRequired,是否指定了控件?

这就是问题:

 label1.Text = i.ToString(); 

您正在尝试更改BackgroundWorker的标签文本,该文本未在UI线程上运行。 BackgroundWorker是在那里完成所有非UI工作,使用ReportProgress定期“返回”UI线程并使用您正在进行的进度更新UI。

因此您需要更改BwProgressChanged label1.Text或者您需要像使用任何其他后台线程一样使用Control.Invoke / BeginInvoke

 // Don't capture a loop variable in a lambda expression... int copy = i; Action updateLabel = () => label1.Text = copy.ToString(); label1.BeginInvoke(updateLabel); 

有关复制部分的更多信息,请参阅Eric Lippert的博客文章“关闭循环变量被认为有害” 。 在这种特殊情况下,它只是一个问题,因为我正在使用BeginInvoke 。 这可以改为:

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

…但是现在后台工作人员总是会等待UI继续前进,这在现实生活中通常不是你想要的。 我通常更喜欢BeginInvoke不是Invoke

使用这个代码我会工作

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

您正在从backgroundworker线程中访问您的标签 – 已在GUI线程上创建。 不允许从创建控件之外的线程访问Windows控件; 因此你得到了例外。

您不应该直接访问标签,而应该从您的线程中引发一个事件,并确保在正确的线程上调用它 – 它向UI发出信号,以便您可以更改标签的内容。

您必须从创建它们的线程中执行控件的方法。 要从其他线程更新它们,请使用Invoke 。 可以在此处找到如何完成此操作的示例。 您还应该在MSDN上阅读使用表单和控件的multithreading 。

上述就是C#学习教程:.NET BackGroundWorker – InvalidOperationException:跨线程操作无效分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1269693.html

(0)
上一篇 2022年11月22日
下一篇 2022年11月22日

精彩推荐