Допустим, у меня есть компонент под названием Tasking (который я не могу изменить), который предоставляет метод DoTask, который выполняет некоторые, возможно, длительные вычисления и возвращает результат через событие TaskCompleted. Обычно это вызывается в форме окна, которую пользователь закрывает после получения результатов.
В моем конкретном сценарии мне нужно связать некоторые данные (запись базы данных) с данными, возвращенными в TaskCompleted, и использовать их для обновления записи базы данных.
Я исследовал использование AutoResetEvent для уведомления, когда событие обрабатывается. Проблема в том, что AutoResetEvent.WaitOne () заблокируется, и обработчик событий никогда не будет вызван. Обычно AutoResetEvents вызывается как отдельный поток, поэтому я предполагаю, что это означает, что обработчик событий находится в том же потоке, что и вызывающий метод.
По сути, я хочу превратить асинхронный вызов, в котором результаты возвращаются через событие, в синхронный вызов (т. Е. Вызвать DoSyncTask из другого класса) путем блокировки до тех пор, пока событие не будет обработано, а результаты не будут помещены в местоположение, доступное для обработчик события и метод, который вызвал метод, который начал асинхронный вызов.
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;
}
}
Мне просто нужно повторить это поведение в оконной службе, где Application.Run не вызывается и объект ApplicationContext недоступен.