This is a mirror of official site: http://jasper-net.blogspot.com/

Invoking events without worrying about cross-thread exceptions

| Thursday, May 13, 2010
InvalidOperationException:"Cross-thread operation not valid: Control '<name>' accessed from a thread other than the thread it was created on."

This exception is something often seen by someone who needs work done on a background thread to leave the application UI responsive to users and maybe even allow the user to cancel the current opperation, while changing properties of controls on the UI from within the background opperation.

I will explain in this a solution in dealing with this particular problem, given a scenario in which the solution is appopriate, where I use extension methods to provide a general solution to the problem.

Background

It should be noted that when particular opperations need to be executed in the background, a the BackgroundWorker is by far the best way to accomplish this.

However, it is not always possible to use the background worker 'as is' and you could even have a need to write your own thread handling classes. This is where the following extension method comes in handy.

The problem

Consider the scenario in which you want to wrap a BackgroundWorker and provide an extra event that reports a status message of the work being done in the worker.

public class ThreadedCall
{

// The worker being wrapped by our class
private BackgroundWorker bw;

// Our new event that will be called whenever our class wants to report a status
public event StatusChangedEventHandler StatusChanged;

// The entry point of our class to start background opperation
public void Start()
{

bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync();
}

// The method that does the actual work, run inside our wrapped worker
void bw_DoWork(object sender, DoWorkEventArgs e)
{

// Report a status here
if (StatusChanged!= null) StatusChanged.Invoke(this,new StatusChangedEventArgs("Phase 1"));
Thread.Sleep(100);  // Do some work

// Report another status here
if (StatusChanged!= null) StatusChanged.Invoke(this,new StatusChangedEventArgs("Phase 2"));
}
}

Our event handler code:

// Delegate to eventhandler that takes a StatusChangedEventArgs as paramater
public delegate void StatusChangedEventHandler(object sender, StatusChangedEventArgs e);

public class StatusChangedEventArgs : EventArgs
{
private string status;

// The status property added to the eventargs used to supply status to the callee
public string Status
{
get { return status; }
set { status = value; }
}

public StatusChangedEventArgs(string status)
{
this.status = status;
}
}

Some code to test our class (The UI code):

private void button1_Click(object sender, EventArgs e)
{

// Instantiate and start or worker wrapper
ThreadedCall t = new ThreadedCall();
t.StatusChanged += new StatusChangedEventHandler(t_StatusChanged);
t.Start();
}

void t_StatusChanged(object sender, StatusChangedEventArgs e)
{
// The following line will raise an exception!
textBox1.Text = string.Format("Status: {0}", e.Status);
}


Read more: Codeproject

Posted via email from jasper22's posterous

0 comments: