Спрашивая: «Как я могу дать команду BackgroundWorker
выполнить работу, а затем ПОДОЖДИТЬ, чтобы рабочий завершил работу, сохраняя при этом графический интерфейс?» действительно спрашивает "Как я могу использовать BackgroundWorker
?". Вот что BackgroundWorker
делает .
Когда вы пишете фоновое задание, вы в основном разбиваете метод на четыре части:
- Подготовка к запуску задачи.
- Сама задача.
- Сообщение о прогрессе в пользовательский интерфейс во время выполнения задачи.
- Очистить вещи, когда задача выполнена.
Итак, вам нужно написать четыре метода. Первый - это метод, который создает BackgroundWorker
, добавляет обработчики событий к его событиям DoWork
, ProgressChanged
и RunWorkerCompleted
, переводит пользовательский интерфейс в любое состояние, в котором он должен находиться во время выполнения задачи, и вызывает RunWorkerAsync
чтобы запустить задачу.
Остальные три являются этими тремя обработчиками событий. DoWork
- это DoWorkEventHandler
, который выполняет эту работу и вызывает ReportProgress
всякий раз, когда ему необходимо сообщить о своем прогрессе в пользовательский интерфейс. ProgressChanged
- это ProgressChangedEventHandler
, который фактически обновляет интерфейс при вызове ReportProgress
. И RunWorkerCompleted
- это RunWorkerCompletedEventHandler
, который сообщает UI, что работа выполнена.
Вот и все.
Ну, не совсем все . Во-первых, вы должны убедиться, что вы проверили и обработали свойство Error
в вашем обработчике завершения. Если вы этого не сделаете, у вас не будет возможности узнать, что ваш метод do-work вызвал исключение, так как это не происходит в потоке пользовательского интерфейса и, следовательно, не вызывает исключение, которое вы видите. (Он отобразится в окне «Вывод», если вы ищете его.)
Во-вторых, вы должны убедиться, что DoWorkEventHandler
ничего не касается в пользовательском интерфейсе. Это может быть сложно, если вы используете шаблон MVVM, и вы не запланировали эту непредвиденную ситуацию, потому что благодаря магии привязки данных у вас, вероятно, есть вещи в вашей модели, которые обновляют представления, с которыми связан пользовательский интерфейс, что означает манипулирование моделью в вашем рабочем методе - это манипулирование пользовательским интерфейсом. Предполагая, что вы реализуете INotifyPropertyChanged
, хорошим способом избежать проблем здесь является создание механизма, при котором ваши представления не генерируют события PropertyChanged
во время выполнения фоновой задачи.
Вам также необходимо выяснить, какие части пользовательского интерфейса следует отключить во время выполнения задачи. Это зависит от вашего пользовательского интерфейса. Ответ может быть «все это», а может и нет. Одной из особенностей привлекательности использования модальной формы для вашего индикатора прогресса является то, что он избавляет вас от необходимости разбираться в этом, поскольку весь пользовательский интерфейс отключен, пока модальная форма открыта. Если вы отключаете элементы управления или отключаете уведомления об изменении свойств в методе запуска, вам необходимо снова включить их в методе завершения.
И помните: любые обновления, которые активные части вашего пользовательского интерфейса вносят в вашу модель данных, являются потенциальным источником межпоточных ошибок доступа к данным. Если ваш пользовательский интерфейс и фоновый поток когда-либо обновляют один и тот же объект, случаются плохие вещи - они особенно плохи, если вы не обработали свойство Error
в обработчике завершения, а исключение между потоками убивает фоновую задачу без вашего зная это. Если это звучит так, как будто я остановился на этом, то это потому, что я потерял много часов своей жизни из-за того, что сделал эту вещь неправильно.