简体   繁体   English

无法在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);
    }
}

First, I tried to set value for the textbox tbxResult on main thread inside BackgroundWorker, but it did not work, then I use delegate to assign the textbox value from main thread, but it does not work too... 首先,我尝试在BackgroundWorker内的主线程上设置文本框tbxResult的值,但是它不起作用,然后我使用委托从主线程分配文本框值,但它也无法正常工作...

Please help me... what was wrong? 请帮我...怎么了?

Hope that logic make sense. 希望逻辑有道理。 But the declaration of delegate is wrong you have to specify the return type in the declaration of SetStatus to make it work. 但是委托声明是错误的,您必须在SetStatus声明中指定返回类型以使其起作用。 So change the declaration like the following: 因此,如下更改声明:

public delegate void SetStatus (string status);

Still you are getting exception( IllegalCrossThreadCallException as René Vogt mentioned in the comment) means you can define the event handler like the following: 仍然会收到异常(注释中提到的IllegalCrossThreadCallExceptionRené Vogt )意味着您可以定义事件处理程序,如下所示:

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

 };

We need to invoke the method again using the main UI thread. 我们需要使用主UI线程再次调用该方法。 Take a look for more info Usage of MethodInvoker in C# 看看更多信息C#中MethodInvoker的用法

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

In general I think BackgroundWorker is obsolete and it's better to use the async/await pattern. 总的来说,我认为BackgroundWorker已过时,最好使用async/await模式。 But that would be too broad an answer. 但这将是一个过于宽泛的答案。

So the immediate answer is: your event handler is not executed on the UI thread, but still on the background worker's thread. 因此,直接的答案是:您的事件处理程序不在UI线程上执行,但仍在后台工作线程上执行。 The normal way to reinvoke actions on the ui thread from a background worker is to use it's ReportProgress method: 从后台工作程序重新调用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 event on the UI thread, so you can assign text to your textbox. ReportProgress()UI线程上调用ProgressChanged事件,因此您可以将文本分配给文本框。 Remember to set WorkerReportsProgress to true . 记住将WorkerReportsProgress设置为true

Use InvokeRequred like this ( or with your delegate): 像这样使用InvokeRequred(或与您的代表一起使用):

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

ps: also see Anonymous method in Invoke call ps:另请参阅Invoke调用中的匿名方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM