Класс BackgroundWorker может запустить отдельный поток, которому обычно поручают какую-нибудь фоновую продолжительную работу. Эта возможность позволяет сохранить работоспособность интерфейса пользователя (основной поток программы не блокируется), когда программа производит некоторые действия, требующие блокировки на ожидание какого-то события.
Цикл потока BackgroundWorker запускается в обработчике события DoWork, (OnDoWork). Внимание: из этого обработчика нельзя менять пользовательский интерфейс, иначе возникнет конфликт с основным потоком программмы! Общение с пользовательским интерфейсом внутри потока DoWork возможно только через вызовы метода ReportProgress, что генерирует события ProgressChanged, которые можно обработать в потоке класса формы (свойство WorkerReportsProgress должно быть установлено при этом в true). Как начать работать с BackgroundWorker:
1. Бросаем на форму компонент BackgroundWorker (BackgroundWorker1).
2. В Form1_Load инициализируем BackgroundWorker:
//разрешение срабатывания событий ProgressChanged
BackgroundWorker1->WorkerReportsProgress = true;
//запуск тела DoWork
BackgroundWorker1->RunWorkerAsync();
3. Заходим в события BackgroundWorker1, и добавляем обработчики DoWork, ProgressChanged, RunWorkerCompleted.
4. Пишем в теле DoWork алгоритм работы BackgroundWorker наподобие следующего:
//////////////////////////////////////////////////////////////////////////////////
// Построение списка имеющихся портов
private: System::Void BackgroundWorker1_DoWork
(System::Object^ sender,
System::ComponentModel::DoWorkEventArgs^ e)
{
BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);
applog->Write("backgroundWorker DoWork");
for(int i=1;i<100;++i)
{
sprintf_s(h411->CommName, COMM_NAME_LEN, "COM%d", i);
if(h411->comport->Open(i,9600))
worker->ReportProgress(i);
h411->comport->Close();
}
}
Здесь вызовы ReportProgress будут генерить события прогресса ProgressChanged.
5. Пишем тело обработчика события ProgressChanged наподобие такого:
//////////////////////////////////////////////////////////////////////////////////
// Обработчик события изменения статуса поиска портов
private: System::Void BackgroundWorker1_Changed
(System::Object^ sender,
System::ComponentModel::ProgressChangedEventArgs^ e)
{
toolStripProgressBar1->Value = e->ProgressPercentage;
}
Здесь e->ProgressPercentage получает значение переменной i, через которую вызовом ReportProgress было передано значение прогресса.
6. Можно останавливать BackgroundWorker, если вызвать его метод CancelAsync():
BackgroundWorker1->CancelAsync();
Чтобы остановка сработала, нужно чтобы свойство WorkerSupportsCancellation было установлено в true. Кроме того, в теле цикла DoWork экземпляра BackgroundWorker нужно организовать проверку свойства CancellationPending, и если оно true, то прерывать выполнение цикла. Пример:
private: System::Void BackgroundWorker1_DoWork
(System::Object^ sender,
System::ComponentModel::DoWorkEventArgs^ e)
{
BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);
applog->Write("bBackgroundWorker1_DoWork START");
for(idxOper=0; idxOper < dataGridView1->RowCount; idxOper++)
{
if (worker->CancellationPending)
break;
worker->ReportProgress(idxOper*100 / dataGridView1->RowCount);
Sleep(200);
}
applog->Write("BackgroundWorker1_DoWork EXIT");
}
7. При завершении работы BackgroundWorker будет автоматически срабатывать событие RunWorkerCompleted. Оно срабатывает и при вызове CancelAsync(), если обработчик DoWork был завершен. Пример обработчика события завершения:
private: System::Void BackgroundWorker1_RunWorkerCompleted
(System::Object^ sender,
System::ComponentModel::RunWorkerCompletedEventArgs^ e)
{
applog->Write("bwIterateCalibr_RunWorkerCompleted");
}
|