0

Following from this question: Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on

I have created a helper class to wrap up the procedure:

public class FormObject
{
    private readonly Form _referenceForm;
    public delegate void SetTextCallback(string text);
    private readonly Control _control;

    public FormObject(Form referenceForm, Control control)
    {
        _referenceForm = referenceForm;
        _control = control;
    }

    public void WriteToControl(string text)
    {
        if (_control.InvokeRequired)
        {
            SetTextCallback d = WriteToControl;
            _referenceForm.Invoke(d, new object[] { text });
        }
        else
        {
            _control.Text = text;
        }
    }
}

Which I call like so:

FormObject fo = new FormObject(this, txtOutput);
fo.WriteToControl("message");

However, the app hangs on the following line:

_referenceForm.Invoke(d, new object[] { text });

There is no error thrown, and waiting doesn't do anything . What am I not seeing here?

-- Edit --
For context, this is a client TCP application connecting to a TCP server. I want to display the resulting message received from the server into the txtOutput.

The application loads and runs correctly, and this invoking call only gets called on a button click.

Here is my current threads when I approach the Invoke:

enter image description here

Community
  • 1
  • 1
TheGeekZn
  • 3,696
  • 10
  • 55
  • 91
  • Where is multi-threading involved here? – Patrick Hofman Jun 10 '15 at 09:15
  • Sounds like your form (or rather, application message loop) is busy. Are you doing this as part of some dialog, for example? Is the `referenceForm` shown, and created and started from something that runs in `Application.Run`? Is there some code on the GUI thread that's waiting for results of this operation? Try pausing the app in the debugger when the hang occurs - switch to the GUI thread. What is it doing? – Luaan Jun 10 '15 at 09:16
  • Control.Invoke() is a pretty dangerous method, very apt to cause deadlock. And very often used wrong, you only really need it when you need its return value. Clearly you don't. Use the debugger's Debug > Windows > Threads window to see what the UI thread is doing to cause the deadlock. Never block the UI thread, never wait for a thread to complete. And use BeginInvoke() instead to avoid unnecessary risk. And always favor the BackgroundWorker or Task classes to do this. – Hans Passant Jun 10 '15 at 09:26
  • @PatrickHofman I tried to set the control directly, but it said it was being called from another thread. I'm using it to display results from within a TCP Connection – TheGeekZn Jun 10 '15 at 10:22

1 Answers1

1

Something like this would work.

    if (_control.InvokeRequired)
    {
       IAsyncResult result = _control.BeginInvoke((Action)(() => control.text = text));
       _control.EndInvoke(result);
    }
    else
    {
        _control.Text = text;
    }
Blaatz0r
  • 1,205
  • 1
  • 12
  • 24