C#. Windows Forms. Элемент управления BackgroundWorker. Отображение прогресса выполненных работ. Отмена выполнения потока




Элемент управления BackgroundWorker. Отображение прогресса выполненных работ. Отмена выполнения потока

Данная тема есть подолжением темы:


Содержание


Поиск на других ресурсах:

1. Схема визуализации прогресса выполненной работы в потоке

На рисунке 1 изображена схема по которой происходит взаимодействие между обработчиками событий для отображения прогресса в потоке (фоновой операции). На основе данной схемы описывается алгоритм, описывающий прогресс выполненных работ (смотрите п.2).

C#. Windows Forms. Элемент управления BackgroundWorker. Визуализация прогресса выполненных работ

Рисунок 1. Визуализация прогресса выполненных работ

 

2. Алгоритм визуализации прогресса выполненных работ

Для отображения прогресса выполненной работы (хода выполнения) в потоке, нужно использовать следующие элементы класса BackgroundWorker:

  • свойство WorkerReportProgress;
  • метод ReportProgress().

Последовательность действий, реализующих отображение прогресса выполнения потока, следующая.

1. В режиме проектирования задать свойство WorkerReportProgress = true.

2. В обработчике события DoWork вызвать метод ReportProgress, в котором указать процент выполненной работы.

Например, если в потоке выполняется обычный цикл от 1 до 100, то код установки процента будет примерно таким:

// Обработчик события DoWork
private void backgroundWorker1_DoWork(...)
{
  // ...

  for (i = 1; i<=100; i++)
  {
    // Действия, выполняемые в цикле
    // ...

    // Вызвать обработчик события ProgressChanged
    try
    {
      backgroundWorker1.ReportProgress((i*100)/100);
    }
    catch(InvalidOperationException exception)
    {
      MessageBox.Show(exception.Message);
    }
  }
}

здесь backgroundWorker1 – название экземпляра потока выполнения для которого нужно реализовать отображение хода выполнения задачи.

3. В обработчике события ProgressChanged отобразить значение процента в некотором визуальном компоненте. Само значение процента получено из экземпляра e класса данных ProgressChangeEventArgs.

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  // Отобразить процент в label1.Text
  label1.Text = Convert.ToString(e.ProgressPercentage) + "%";

  // Отобразить изменение процента в progressBar1.Value
  progressBar2.Value = e.ProgressPercentage;
}

здесь

  • label1 — элемент управления, выводящий значение процента (например 28%);
  • ProgressChangeEventArgs — класс, представляющий данные для события ProgressChanged;
  • e.ProgressPercentage — свойство, которое возвращает целочисленный процент, который был сформирован в п. 2 алгоритма при вызове метода ReportProgress().

 

3. Отмена выполнения потока. Схема взаимодействия между обработчиками событий

При выполнении некоторого потока (фоновой операции), пользователь имеет возможность отменить выполнение этого потока. Класс BackgroundWorker имеет все необходимые средства для контроля за отменой выполнения потока. На рисунке 2 изображена схема взаимодействия между обработчиками событий, которые задействованы в отмене выполнения потока.

C#. Windows Forms. Класс BackgroundWorker. Отмена выполнения потока

Рисунок 2. Отмена выполнения потока. Взаимодействие между обработчиками событий

 

4. Последовательность действий (алгоритм) отмены выполнения потока

Здесь описывается общий алгоритм действий, которые нужно выполнить чтобы корректно обработать отмену выполнения потока (фоновой операции). Чтобы отменить поток используются следующие взаимосвязанные члены класса BackgroundWorker:

  • свойство WorkerSupportsCancellation;
  • метод CancelAsync();
  • свойство CancellationPending.

Алгоритм, реализующий корректную отмену выполнения потока, следующий.

1. Установить свойство WorkerSupportsCancellation = true. Это позволит использовать средства остановки (отмены выполнения) потока.

2. В обработчике события щелчка на кнопке остановки потока вызвать метод CancelAsync()

// Отменить выполнение потока
private void button2_Click(object sender, EventArgs e)
{
  try
  {
    backgroundWorker1.CancelAsync();
  }
  catch(InvalidOperationException exception)
  {
    // Вывести сообщение об ошибке
    MessageBox.Show(exception.Message);
  }
}

Теперь при клике на кнопке остановки потока будет генерироваться соответствующий запрос в обработчике события DoWork.

3. В обработчике события DoWork реализовать проверку на то, была ли вызвана команда остановки потока. Это осуществляется путем проверки свойства CancellationPending.

В простейшем случае для обычного цикла код остановки потока будет выглядеть следующим образом:

...

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{

  ...

  // Цикл выполнения потока
  for (int i=0; i<1000; i++)
  {

    ...

    // Проверка, была ли выполнена команда отмены выполнения потока
    if (backgroundWorker1.CancellationPending)
      break; // если был запрос на остановку потока, то выход из цикла
  }
}

...

4. В обработчике события RunWorkerCompleted выполнить соответствующие действия после завершения выполнения потока.

Для того, чтобы распознать способ завершения потока можно ввести дополнительную внутреннюю переменную, которая будет принимать соответствующее значение.

В нижеследующем коде в класс формы введена внутренняя переменная fCancelled. Эта переменная определяет, был ли отменен поток пользователем и формируется ли в обработчике события DoWork. Текст обработчика события следующий.

Результат завершения выполнения потока (нормальное завершение или отменена пользователем) выводится в обработчике события RunWorkerCompleted. Также в этом обработчике переменная fCancelled устанавливается в исходное состояние.

// Класс формы
public partial class Form1 : Form
{
  // Определяет, как был завершен поток
  bool fCancelled = false; // если fCancelled=false, то выполнение потока было отменено пользователем

  ...

  // Выполнение потока - обработчик события DoWork - устанавливает значение fCancelled
  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
  {

    ...

    // Цикл выполнения потока
    for (int i=0; i<1000; i++)
    {

      ...

      // Проверка, была ли выполнена команда отмены выполнения потока
      if (backgroundWorker1.CancellationPending)
      {
        // указать, что выполнение потока было отменено пользователем
        fCancelled = true;

        // завершить поток, выйти из цикла
        break;
      }
    }
  }

  // Обработчик события завершения потока
  private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
    // Проверка того, как был завершен поток
    if (fCancelled)
      label1.Text = "The thread was cancelled";
    else
      label1.Text = "The thread was completed normally";

    // Вернуть fCancelled в начальное значение
    fCancelled = false;
  }

  ...

}

 


Связанные темы