无法在 backgroundworker 中为文本框赋值(c# winform)

Can not assign value for textbox in backgroundworker (c# winform)

public class Form1
{
    public delegate void SetStatus (string status);
    public event SetStatus SetStatusHandler;

    public BackgroundWorker bw = new BackgroundWorker();

    public Form1()
    {
        tbxResult.Text = "Assign text Ok";

        SetStatusHandler += delegate(string status)
            {
                tbxResult.Text = status; // can not assign
            };

        bw.DoWork += backgroundWorker_DoWork;
        bw.RunWorkerAsync();

    }

    void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        var status = "assign some value";
        SetStatusHandler(status);
    }
}

首先,我尝试在 BackgroundWorker 内的主线程上为文本框 tbxResult 设置值,但它没有用,然后我使用委托从主线程分配文本框值,但它也不起作用...

请帮帮我...怎么了?

希望逻辑合理。但是委托的声明是错误的,你必须在 SetStatus 的声明中指定 return 类型才能使其工作。所以像下面这样更改声明:

public delegate void SetStatus (string status);

仍然出现异常(IllegalCrossThreadCallException,如评论中提到的 René Vogt )意味着您可以像下面这样定义事件处理程序:

SetStatusHandler += delegate(string status)
 {
     tbxResult.Invoke(new MethodInvoker(delegate
     {
         tbxResult.Text = status;
     }));

 };

我们需要使用主 UI 线程再次调用该方法。查看更多信息 Usage of MethodInvoker in C#

tbxResult.Invoke((MethodInvoker) delegate
    {
        tbxResult.Text = status;
    });

总的来说,我认为 BackgroundWorker 已经过时了,最好使用 async/await 模式。但这太宽泛了。

所以直接的答案是:你的事件处理程序不是在UI线程上执行的,而是在后台工作线程上执行的。从后台工作者重新调用 ui 线程上的操作的正常方法是使用它的 ReportProgress 方法:

public Form1()
{
    tbxResult.Text = "Assign text Ok";
    bw.DoWork += backgroundWorker_DoWork;
    bw.WorkerReportsProgress = true;
    bw.ProgressChanged += (sender, e) => tbxResult.Text = (string)e.UserState;
    bw.RunWorkerAsync();
}

void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    var status = "assign some value";
    bw.ReportProgress(0, status);
}

ReportProgress() invokes the ProgressChanged UI 线程上的事件,因此您可以将文本分配给文本框。记得将 WorkerReportsProgress 设置为 true.

像这样使用 InvokeRequred(或与您的委托一起使用):

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        if (textBox1.InvokeRequired)
        {
            textBox1.Invoke((MethodInvoker) delegate { textBox1.Text = @"AAAAAA"; });
        }
        else
        {
            textBox1.Text = @"AAAAAA";
        }
    }

ps:另见Anonymous method in Invoke call