.NET的BackgroundWorker - InvalidOperationException异常:跨线程操作无效 [英] .NET BackGroundWorker - InvalidOperationException : Cross-thread operation not valid

查看:181
本文介绍了.NET的BackgroundWorker - InvalidOperationException异常:跨线程操作无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个项目在.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 ,这是不是在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆