BackgroundWorker завершает работу перед DoWork
Я использую фоновый рабочий для обработки загрузки файла, чтобы предотвратить зависание пользовательского интерфейса, однако кажется, что RunWorkerCompleted
заканчивается перед моим DoWork
событие завершено (выдает ошибки при выходе из диалога)... что-то я делаю не так? Мне лучше делать это над задачей?
public static <T> LoadDesign(string xmlPath)
{
PleaseWait pw = new PleaseWait(xmlPath);
pw.ShowDialog();
return pw.design;
}
private PleaseWait(string xmlFile)
{
InitializeComponent();
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += (s, e) =>
{
design = (Cast)DllCall containing XmlSerializer.Deserialize(...,xmlFile);
};
bw.RunWorkerCompleted += (s, e) => {
//Exit please wait dialog
this.Close();
};
if (!bw.IsBusy)
bw.RunWorkerAsync();
}
Я полагаю, что проблема может быть связана с тем фактом, что мой фоновый работник вызывает dll и не ждет ответа. Я пытался добавить проверки, такие как while(design == null)
но безрезультатно..
Edit2 Ошибка - NRE, так как дизайн не был загружен, я могу легко исправить это, но вместо этого предпочел бы работать с потоками.
3 ответа
Есть много маленьких ошибок. Учитывая, что мы, вероятно, не смотрим на реальный код и что у нас нет отладчика с окном Call Stack, чтобы увидеть, где он действительно падает, любой из них может быть фактором.
Тестирование bw.IsBusy и не запускать работника, когда это правда, является серьезной ошибкой. Он никогда не может быть занят в опубликованном коде, но если это действительно возможно для его истинности, то в вашем коде есть неприятная ошибка. Поскольку вы действительно подписались на события на занятого работника. Теперь обработчик событий RunWorkerCompleted будет выполняться дважды.
Использование метода Close() для закрытия диалога некорректно. Диалог должен быть закрыт путем назначения его свойства DialogResult. Не самая серьезная ошибка, но, тем не менее, неправильная.
В коде есть гонка, которую рабочий может завершить до того, как появится диалоговое окно. Диалог может быть закрыт только тогда, когда было создано его собственное окно. Другими словами, IsHandleCreated должен быть истинным. Вы должны заблокировать это, чтобы этого никогда не произошло. Подпишите диалоговое событие Load, чтобы начать работу.
Вы слепо предполагаете, что работник закончит работу и даст результат. Это не будет иметь место, когда его метод DoWork умер от исключения. Который перехватывается BackgroundWorker и передается обработчику события RunWorkerCompleted в качестве свойства e.Error. Вы должны проверить это свойство и сделать что-то разумное, если оно не равно нулю.
Судя по комментариям, я предполагаю, что причиной является последняя пуля. Вы отлаживаете это с помощью Debug + Exceptions, отметьте флажок Thrown для исключений CLR. Отладчик теперь остановится, когда возникнет исключение, что позволит вам выяснить, что пошло не так.
Если вы вызываете другую асинхронную функцию в событии BackgroundWorker _DoWork,
нравиться;
private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
somethingsToDoAsync();
// somethingsToDoAsync() function is to ASYNC
}
_RunWorkerCompleted срабатывает еще до завершения события _Dowork.
Измените другую функцию somethingsToDoAsync(), чтобы она не была асинхронной.
Возможно, ваш фоновый работник на самом деле не займет много времени и завершит работу, прежде чем появится диалоговое окно. Я бы предложил перенести инициализацию фонового рабочего и запустить код PleaseWait
Form_Load или Form_Shown