Como invocar manipulador de eventos dentro de um retorno de chamada assíncrono de tal forma que é executado no segmento de chamada
Eu estou trabalhando em um projeto VS / solução que é usado por diferentes aplicativos. Meu trabalho é refatorar o projeto e alterá-lo de usar o método xxxAsync para usar o BeginInvoke.
Eu cheguei a algo semelhante ao seguinte código:
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;
}
}
}
Eu testei isso em um novo projeto de interface do usuário que criei. O projeto da interface do usuário contém um botão e um controle de rótulo. A interface do usuário tem o seguinte código:
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;
}
Depois de executar isso, eu encontrei a exceção cross-thread dizendo que o controle 'label1' está sendo acessado de outro thread além do thread que foi criado.
Existe uma maneira de invocar o manipulador de eventos OnTaskCompleted no mesmo segmento que chama o método BeginInvoke? Eu sei que eu poderia apenas usar o InvokeRequired do formulário e chamar BeginInvoke do formulário como o seguinte:
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;
}
Mas a solução acima exigirá que eu pergunte e aplique essa solução à outra equipe de desenvolvimento que manipula aplicativos que usam meu projeto / solução. Esses outros desenvolvedores não devem ser obrigados a saber que os métodos conectados ao manipulador de eventos estão sendo executados a partir de segmentos diferentes.
Desde já, obrigado.