Розглянемо гіпотетичний метод об’єкта, який робить речі для вас:
public class DoesStuff
{
BackgroundWorker _worker = new BackgroundWorker();
...
public void CancelDoingStuff()
{
_worker.CancelAsync();
//todo: Figure out a way to wait for BackgroundWorker to be cancelled.
}
}
Як можна чекати, коли буде виконано BackgroundWorker?
У минулому люди намагалися:
while (_worker.IsBusy)
{
Sleep(100);
}
Але це тупикові місця , оскільки IsBusy
не знімається до моменту RunWorkerCompleted
обробки події, і ця подія не може бути оброблена, поки програма не працює. Додаток не працюватиме, поки працівник не закінчиться. (Плюс, це зайнята петля - огидна.)
Інші додали пропозицію, включаючи його:
while (_worker.IsBusy)
{
Application.DoEvents();
}
Проблема в тому, що Application.DoEvents()
викликає обробку повідомлень, що перебувають у черзі, що спричиняють проблеми повторного вступу (.NET is re-entrant).
Я би сподівався використати якесь рішення, що стосується об'єктів синхронізації подій, де код чекає події, яку RunWorkerCompleted
встановлює обробник подій працівника . Щось на зразок:
Event _workerDoneEvent = new WaitHandle();
public void CancelDoingStuff()
{
_worker.CancelAsync();
_workerDoneEvent.WaitOne();
}
private void RunWorkerCompletedEventHandler(sender object, RunWorkerCompletedEventArgs e)
{
_workerDoneEvent.SetEvent();
}
Але я повернувся в глухий кут: обробник подій не може запускатися, поки програма не працює, і програма не вийде з ладу, оскільки її чекає подія.
Тож як ви можете чекати закінчення BackgroundWorker?
Оновлення Люди, схоже, збентежені цим питанням. Вони, здається, думають, що я буду використовувати BackgroundWorker як:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += MyWork;
worker.RunWorkerAsync();
WaitForWorkerToFinish(worker);
Це не так, це не те, що я роблю, і це не те, що тут просять. Якби це було так, не було б сенсу використовувати фонового працівника.