0
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...

Please help me... what was wrong?

  • You do not try to set it from main thread. Calling a delegate does not switch the thread. Set `backgroundWorker.WorkerReportsProgress` to `true`, subscribe to `backgroundWorker.ProgressChanged` event and call `backgroundWorker.ReportProgress()` instead of `SetStatusHandler`. Btw: backgroundworker is kind of obsolete, try to use `async/await` instead. – René Vogt Feb 02 '17 at 07:11
  • You should call `Control.Invoke` for this purpose. Read for more detail [Control.Invoke](https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx) – M. Adeel Khalid Feb 02 '17 at 07:12

4 Answers4

0

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. 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:

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

 };
sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
  • @RenéVogt: But it will update the text box with `"assign some value"` – sujith karivelil Feb 02 '17 at 07:14
  • The context of problem is different. – M. Adeel Khalid Feb 02 '17 at 07:14
  • @un-lucky: Thank you! Could you tell me the difference between "tbxResult.text = status" and "tbxResult.Invoke(new MethodInvoker(delegate...". The first is executed in backgroundworker thead and the second is on main thread, right? – Hoàng Trần Huy Feb 02 '17 at 07:35
  • @HoàngTrầnHuy: which will `Executes the specified delegate on the thread that owns the control's underlying window handle.` see the [Documentation](https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx) – sujith karivelil Feb 02 '17 at 07:38
0

We need to invoke the method again using the main UI thread. Take a look for more info Usage of MethodInvoker in C#

tbxResult.Invoke((MethodInvoker) delegate
    {
        tbxResult.Text = status;
    });
kgzdev
  • 2,770
  • 2
  • 18
  • 35
  • 1
    Its better to write some description too. – M. Adeel Khalid Feb 02 '17 at 07:15
  • Yes, we need to invoke the method again using the main UI thread. Take a look for more info [Usage of MethodInvoker in C#](http://thebrainyprofessionals.com/2013/03/30/usage-of-methodinvoker-in-c/) – kgzdev Feb 02 '17 at 07:45
0

In general I think BackgroundWorker is obsolete and it's better to use the async/await pattern. 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. The normal way to reinvoke actions on the ui thread from a background worker is to use it's ReportProgress method:

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. Remember to set WorkerReportsProgress to true.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
0

Use InvokeRequred like this ( or with your delegate):

    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

Community
  • 1
  • 1
rud0x1
  • 88
  • 7