gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-30 00:03:33 26 4
gpt4 key购买 nike

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

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

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

但是,结果是一样的。我在 SOF 上搜索,并被告知要使用委托(delegate),但我对此并不熟悉。

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

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 的回答,它确实适用于我的测试项目,但回到我的真实项目,

我的表单布局:

表格 - 选项卡控件 - 表 1 -Tab1面板 -TextBox1

当到达这一行时:

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

当我以编程方式将文本框添加到面板控制时,错误仍然发生。

最后,我用这个代替:

 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 的博客文章,"Closing over the loop variable considered harmful" .在这种特殊情况下,这只是一个问题,因为我使用的是 BeginInvoke。这可以更改为:

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

...但是现在后台工作人员总是在等待 UI catch 进度,然后再继续,这在现实生活中通常不是您想要的。我通常更喜欢 BeginInvoke 而不是 Invoke

关于c# - .NET BackGroundWorker - InvalidOperationException : Cross-thread operation not valid,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7963103/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com