Digamos que tengo un componente llamado Tarea (que no puedo modificar) que expone un método "DoTask" que hace algunos cálculos posiblemente largos y devuelve el resultado a través de un evento TaskCompleted. Normalmente esto se llama en una forma de Windows que el usuario cierra después de que obtiene los resultados.¿Es posible colocar un controlador de eventos en un hilo diferente para la persona que llama?
En mi escenario particular que necesita asociar algunos datos (un registro de la base) con los datos devueltos en TaskCompleted y usarlo para actualizar el registro de base de datos.
que he investigado el uso de AutoResetEvent para notificar cuando se maneja el evento. El problema con eso es AutoResetEvent.WaitOne() se bloqueará y el controlador de eventos nunca se llamará. Normalmente AutoResetEvents se llama ser un hilo separado, así que supongo que eso significa que el controlador de eventos está en el mismo hilo que el método que llama.
Básicamente quiero convertir una llamada asincrónica, donde los resultados se devuelven mediante un evento, en una llamada síncrona (es decir, llamar a DoSyncTask desde otra clase) bloqueando hasta que se maneje el evento y los resultados colocados en una ubicación accesible tanto el controlador de eventos como el método que invocó el método que inició la llamada asincrónica.
public class SyncTask
{
TaskCompletedEventArgs data;
AutoResetEvent taskDone;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
taskDone.WaitOne(); // but something more like Application.DoEvents(); in WinForms.
taskDone.Reset();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}
In a Windows App the following works correctly.
public class SyncTask
{
TaskCompletedEventArgs data;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
while (data == null) Application.DoEvents();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
}
}
que sólo tiene que repetir ese comportamiento en un servicio de ventana, donde Application.Run no se llama y el objeto Application Context no está disponible.
Aquí hay un buen video para entender 'AutoResetEvent' http://www.youtube.com/watch?v=xaaRBh07N34 – Jaider