Powiedzmy, że mam komponent o nazwie Tasking (którego nie mogę zmodyfikować), który ujawnia metodę "DoTask", która wykonuje niektóre długotrwałe obliczenia i zwraca wynik za pośrednictwem zdarzenia TaskCompleted. Zwykle jest to wywoływane w postaci okna, które użytkownik zamyka po uzyskaniu wyników.Czy jest możliwe umieszczenie programu obsługi zdarzeń w innym wątku dla dzwoniącego?
W moim szczególnym scenariuszu muszę powiązać niektóre dane (rekord bazy danych) z danymi zwróconymi w TaskCompleted i użyć go do aktualizacji rekordu bazy danych.
Sprawdziłem użycie AutoResetEvent, aby powiadomić o zdarzeniu. Problem polega na tym, że AutoResetEvent.WaitOne() zostanie zablokowany, a program obsługi zdarzeń nigdy nie zostanie wywołany. Normalnie AutoResetEvents nazywa się osobnym wątkiem, więc myślę, że oznacza to, że procedura obsługi zdarzeń jest w tym samym wątku, co wywoływana metoda.
Zasadniczo chcę, aby wywołanie asynchroniczne, w którym wyniki są zwracane przez zdarzenie, do wywołania synchronicznego (tj. Wywołanie DoSyncTask z innej klasy), blokując do czasu obsługi zdarzenia, a wyniki umieszczone w lokalizacji dostępne dla zarówno procedura obsługi zdarzeń, jak i metoda, która wywołała metodę, która uruchomiła wywołanie asynchroniczne.
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;
}
}
Muszę tylko powtórzyć to zachowanie w usłudze okno, w którym Application.Run nie nazywa, a obiekt ApplicationContext nie jest dostępna.
Oto dobry film, aby zrozumieć "AutoResetEvent" http://www.youtube.com/watch?v=xaaRBh07N34 – Jaider