Tuesday, March 06, 2007

I came across an annoying little thing trying to trigger an event that updates the UI...

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


This happens because the UI runs in a specific thread. Now we create another thread and try to access the UI thread which throws the above exception. There is a solution in msdn but imo its not a good one.

Thus we need to marshal the event from one thread to the other thread as shown below.

the source (just create a new form called form1 and drag a label and a button on it):

ThreadComponent.cs


using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;


namespace WindowsApplication3 {
public delegate void ShowSomethingHandler(string message);


public class ThreadedComponent {
private Thread _Thread;

public ThreadedComponent() {
_Thread = new Thread(Poll);
_Thread.Start();

}

private void Poll() {
int i = 0;
ISynchronizeInvoke invoker = ShowSomething.Target as ISynchronizeInvoke;
while(true) {
if(ShowSomething != null) {

//ShowSomething("Message N°:" + (++i));
if(!invoker.InvokeRequired) {
object[] args = {"Message N°:" + (++i)};
invoker.Invoke(ShowSomething, args);
} else {
ShowSomething("Message N°:" + (++i));
}


}
Thread.Sleep(1000);
}
}

public event ShowSomethingHandler ShowSomething;
}
}



Form1.cs

namespace WindowsApplication3 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e) {
ThreadedComponent c = new ThreadedComponent();
c.ShowSomething += new ShowSomethingHandler(c_ShowSomething);
}

void c_ShowSomething(string message) {
label1.Text = message;
}
}
}