Jak wywołać procedurę obsługi zdarzeń w asynchronicznym wywołaniu zwrotnym, które jest uruchamiane w wątku wywołującym
Pracuję nad projektem / rozwiązaniem VS, które jest używane przez różne aplikacje. Moim zadaniem jest refaktoryzacja projektu i zmiana go z używania metody xxxAsync na używanie BeginInvoke.
Doszedłem do czegoś podobnego do następującego kodu:
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;
}
}
}
Przetestowałem to na nowym projekcie interfejsu użytkownika, który stworzyłem. Projekt interfejsu użytkownika zawiera przycisk i elementy sterujące etykietą. Interfejs użytkownika ma następujący kod:
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;
}
Po uruchomieniu tego problemu natknąłem się na wyjątek między wątkami, mówiąc, że kontrolka „label1” jest dostępna z innego wątku poza wątkiem, który został utworzony.
Czy istnieje sposób, aby wywołać moduł obsługi zdarzenia OnTaskCompleted w tym samym wątku, który wywołuje metodę BeginInvoke? Wiem, że mogę po prostu użyć InvokeRequired formularza i wywołać BeginInvoke formularza w następujący sposób:
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;
}
Ale powyższe rozwiązanie będzie wymagało ode mnie pytania i zastosowania tego rozwiązania do innych zespołów programistycznych obsługujących aplikacje korzystające z mojego projektu / rozwiązania. Nie powinno się wymagać, aby ci inni programiści wiedzieli, że metody podłączone do obsługi zdarzeń działają z innego wątku.
Z góry dziękuję.