0

In my apps i use backgroundWorker, to set text in some TextBox, I need first to invoke that TextBox.

First I use:

            if (someTextBox.InvokeRequired)
            {
                someTextBox.Invoke((MethodInvoker)delegate
                {
                    someTextBox.Text = "some_text";
                });
            }
            else
            {
                    someTextBox.Text = "some_text";
            }

This method work for me fine, but because i have multiple TextBox-es i wrote:

    private void invComp(TextBox txtBox, String str)
    {
        if (txtBox.InvokeRequired)
        {
            txtBox.Invoke((MethodInvoker)delegate
            {
                txtBox.Text = str;
            });
        }
        else
        {
            txtBox.Text = str;
        }
    }

It is better to invoke it on this way? (invComp(someTextBox, "some_text"); Or maybe i have some third, bether , way?

I invoke some buttons to, I was think to write something like this for button to, if this is ok?

Tnx

Frink
  • 221
  • 4
  • 23
  • 1
    Take a look at [this](http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c) – Daniel J.G. Jul 18 '14 at 09:40

2 Answers2

5

Control.InvokeRequired suffers from cargo cult. You are updating a control from a worker thread, you know that invoking is required. So there is absolutely no point in testing it. Except for one reason, there is something fundamentally wrong when it is false. Which happens a lot more often than programmers like, forgetting to stop a worker when the user closes the window is a traditional bug. This causes all kind of mayhem, you want to know about it:

private void invComp(TextBox txtBox, String str) {
    if (!this.InvokeRequired) throw new InvalidOperationException("You forgot to stop the worker");
    this.BeginInvoke(new Action(() => txtBox.Text = str));
}

Short and snappy and fail-safe and fast. Good qualities of code. Note that it uses the form's BeginInvoke() method, it doesn't depend on a child control being created. And that it uses BeginInvoke() instead of Invoke(), important to not bog down the worker thread and avoid deadlock. Always avoid Invoke(), it is only required when you need to know a method return value.


A completely different take is to focus on you using BackgroundWorker. It already marshals calls to the UI thread, it is just that the method has a clumsy name. You can get the ProgressChanged event to execute any code, it isn't just good enough to show progress. Write your event handler like this:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
    ((Action)e.UserState).Invoke();
}

Now you can make it execute any code on the UI thread:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
    var worker = (BackgroundWorker)sender;
    //...
    worker.ReportProgress(0, new Action(() => textBox1.Text = "hello"));
}
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
2

You can slightly modify your method, to make it generic, so that you can use if for any control.

    private void invComp<T>(T control, String str) where T: Control
    {
        if (control.InvokeRequired)
        {
            control.Invoke((MethodInvoker)delegate
            {
                control.Text = str;
            });
        }
        else
        {
            control.Text = str;
        }
    }
Nitin Joshi
  • 1,638
  • 1
  • 14
  • 17