Ben Gale
Ben Gale

Reputation: 5361

Setting text boxes thread issues

I'm pretty new at C# so forgive me if this is a bit of a silly question. Anyway I'm writing a little chat application that so far seems to be going well, I've run into a problem that I seem to have fixed but I'm hoping to work out why I need to do it this way.

When I receive a message I want to update a text box so I use:

txtConnectedID.Text = "test";

But I receive this error:

System.InvalidOperationException was unhandled by user code
  Message=Cross-thread operation not valid: Control 'txtConnectedID' accessed from a thread other than the thread it was created on.

Now, I think this has something to do with stopping the method running twice and not updating properly? I'm not 100% on this. So now I have a delegate for a method that accepts a string and I call:

private delegate void stringDelegate(string s);

BeginInvoke(new stringDelegate(writeToIPBox), new object[] { e.ConnectedIP.ToString() });

private void writeToIPBox(string newIP)
        {
            txtConnectedID.Text = newIP;
        }

I'm not sure why I'm doing this, how it's any different. I'm not really happy to just do it this way without knowing why.

Thanks in advance

Upvotes: 2

Views: 286

Answers (4)

Mediator
Mediator

Reputation: 15378

private static void SetText(TextBox tb, string text)
{
    if (tb.InvokeRequired)
    {
        var stDelegate = new StDelegate(SetText);
        tb.Invoke(stDelegate, new object[] { tb, text });
    }
    else
    {
        tb.Text = text;
    }
}

Upvotes: 0

corlettk
corlettk

Reputation: 13574

It took a new minutes of determined googling but I eventually found an "authorative" reference:

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired%28v=vs.90%29.aspx

The short answer (to quote from that page) is: Controls in Windows Forms are bound to a specific thread and are not thread safe.

This article also aludes to how this can be handled "internally"... if control.InvokeRequired (i.e. we've been called from another thread) handle the invocation internally... rather than spreading delegates throughout your code.

Personally I'd never really questioned WHY a delegate was required, I just did it. Good question.

Cheers. Keith.

Upvotes: 0

Ed Swangren
Ed Swangren

Reputation: 124692

You should only attempt to update controls from the thread on which they were created. There are good reasons for this as it is easy to hit a race condition. These controls are not thread safe and this is the runtime helping you out a bit.

Instead, as you have figured out, you need to update it on the UI thread, which is what BeginInvoke is doing; calling the delegate asynchronously on the UI thread.

Upvotes: 1

Botz3000
Botz3000

Reputation: 39620

All controls are owned by the UI thread (of which there is only one), and trying to access them from another thread results in this Exception.

BeginInvoke calls the specified delegate on the UI thread, which is why it works. You can also check if you are on the UI thread by checking txtConnectedID.InvokeRequired.

Upvotes: 0

Related Questions