I am working on a VS project/solution that is used by different applications. My job is to refactor the project and change it from using xxxAsync method to using BeginInvoke.
I came up to something similar to the following code:
public class AsyncTestModel {
private delegate string DoTaskDelegate();
public static EventHandler<TaskCompletedEventArgs> OnTaskCompleted;
public static void InvokeTask() {
DoTaskDelegate taskDelegate = Task;
taskDelegate.BeginInvoke(new AsyncCallback(TaskCallback), null);
}
private static string Task() {
Thread.Sleep(5000);
return "Thread Task successfully completed.";
}
private static void TaskCallback(IAsyncResult ar) {
string result = ((DoTaskDelegate)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate).EndInvoke(ar);
if (OnTaskCompleted != null) {
OnTaskCompleted(null, new TaskCompletedEventArgs(result));
}
}
}
public class TaskCompletedEventArgs : EventArgs {
private string _message;
public TaskCompletedEventArgs(string message) : base() {
_message = message;
}
public string Message {
get {
return _message;
}
}
}
I've tested this on a new UI project I've created. The UI project contains a button and a label controls. The UI has the following code:
private void button1_Click(object sender, EventArgs e) {
AsyncTestModel.OnTaskCompleted += OnTaskCompleted;
AsyncTestModel.InvokeTask();
}
private void OnTaskCompleted(object sender, TaskCompletedEventArgs e) {
UpdateLabel(e.Message);
}
private void UpdateLabel(string message) {
this.label1.Text = message;
}
After running this, I've encountered the cross-thread exception saying the the control 'label1' is being accessed from other thread aside the thread that it was created.
Is there a way for me to invoke the OnTaskCompleted event handler on the same thread that calls the BeginInvoke method? I know I could just use the form's InvokeRequired and call the form's BeginInvoke like the following:
private delegate void DoUpdateLabelDelegate(string message);
private void UpdateLabel(string message) {
if (this.InvokeRequired) {
IAsyncResult ar = this.BeginInvoke(new DoUpdateLabelDelegate(UpdateLabel), message);
this.EndInvoke(ar);
return;
}
this.label1.Text = message;
}
But the solution above will require me to ask and apply that solution to the other development team handling applications that uses my project/solution. Those other developers shouldn't be required to know that the methods hooked to the event handler are running from different thread.
Thanks, in advance.