views:

525

answers:

7

In the following code MessageReceived is on a different thread to label1 and when trying to access it I will get this error:

Cross-thread operation not valid: Control 'label1' accessed from a thread other than the thread it was created on.

foo.MessageReceived += new Agent.MessageReceivedHandler(foo_MessageReceived); 

void foo_MessageReceived(Message message)
{
   label1.Text = message.Body;
}

How can I solve this?

More: apparently I need to use delegate and invoke, but I don't know how, can you please explain in more detail?

A: 

This is totally not helpful. I wish I could vote myself down.

I may be out of date, but from what I remember you aren't allowed to alter anything in the GUI from anything but the main thread.

Jason Punyon
+1  A: 

Delegate updating the label to the thread that created the label instead of trying to update it directly.

Welbog
A: 

You have to go for delegates. Please refer this post

Bharani
+3  A: 

Hopefully this will be closed as an exact duplicate, but if not:

Don't touch the GUI from a non-GUI thread. Use BackgroundWorker and report progress appropriately, or read the WinForms page of my threading article for more direct control (Control.Invoke/BeginInvoke).

Jon Skeet
A: 

In your Agent class, when you raise the MessageReceived event, you'll have to check whether the Target of the event-handler implements ISynchronizeInvoke. If it does, and if the InvokeRequired property returns true, you'll have to invoke the eventhandler.

If you're not using WinForms, but WPF, you cannot rely anymore on ISynchronizeInvoke since the WPF controls do not implement that interface. Instead, you'll have to work with AsyncOperation and AsyncOperatoinManager.

Frederik Gheysels
+1  A: 

You need to use Control.Invoke (or Control.BeginInvoke). First, create a new Windows Forms application and add a label and a button. Double click on the button in Visual Studio to edit it's Click event and add the following code:

    private void button1_Click(object sender, EventArgs e)
    {
        new System.Threading.Thread(new System.Threading.ThreadStart(Run)).Start();
    }

    void Run()
    {
        label1.Invoke(new Action(delegate()
        {
            label1.Text = System.Threading.Thread.CurrentThread.Name + " " + System.DateTime.Now.ToString();
        }));
    }
Joe Erickson
The key piece that is needed from this answer is the Invoke call.
consultutah
A: 

Make always sure you update your GUI on the main thread (GUI thread).

foo.MessageReceived += new Agent.MessageReceivedHandler(foo_MessageReceived);

public delegate void MyDelegate(Message msg);
void foo_MessageReceived(Message message)
{ 
if (IvokeRequired)
{
   BeginInvoke(new MyDelegate(foo_MessageReceived),new object[]{message});
}
else
{
  label1.Text = message.Body;
}
}
Mez