Пошаговое руководство. Реализация формы, в которой выполняется фоновая операция
Если у вас есть операция будет выполняться долго для завершения, и не требуется пользовательский интерфейс (UI) перестает отвечать на запросы или «зависания», можно использовать BackgroundWorker класс для выполнения операции в другом потоке.
В этом пошаговом руководстве показано, как использовать BackgroundWorker класса для выполнения длительных вычислений «в фоновом режиме», а пользовательский интерфейс продолжает отвечать. По завершении работы будет создано приложение, вычисляющее числа Фибоначчи в асинхронном режиме. Несмотря на то что вычисление крупных чисел Фибоначчи может занимать много времени, основной поток пользовательского интерфейса в результате этой задержки прерываться не будет, а форма в ходе вычисления останется рабочей.
В данном пошаговом руководстве представлены следующие задачи.
Создание приложения на базе Windows
Создание BackgroundWorker в форме
Добавление обработчиков асинхронных событий
Добавление отчетов о ходе выполнения и поддержка отмены
Полный код, используемый в этом примере, см. в разделе как: Реализация формы, в который выполняется фоновая операция.
Note
Отображаемые диалоговые окна и команды меню могут отличаться от описанных в справке в зависимости от текущих параметров или выпуска. Чтобы изменить параметры, выберите в меню Сервис пункт Импорт и экспорт параметров . Дополнительные сведения см. в разделе Персонализация интегрированной среды разработки Visual Studio.
Создание проекта
Первым шагом являются создание проекта и настройка формы.
Создание формы, в которой выполняется фоновая операция
Создайте проект приложения на основе Windows с именем
BackgroundWorkerExample
(файл > New > проекта > Visual C# или Visual Basic > классический рабочий стол > Windows Forms Application).В обозревателе решений щелкните правой кнопкой мыши Form1 и выберите в контекстном меню команду Переименовать. Измените имя файла на
FibonacciCalculator
. Чтобы переименовать все ссылки на элемент кода 'Form1
', в соответствующем запросе нажмите кнопку Да.Перетащите NumericUpDown управления из элементов на форму. Задайте Minimum свойства
1
и Maximum свойства91
.Добавьте два Button элементов управления в форму.
Переименуйте первый Button управления
startAsyncButton
и задайте Text свойстваStart Async
. Переименуйте второй Button управленияcancelAsyncButton
и задайте Text свойстваCancel Async
. Задайте его Enabled свойстваfalse
.Создайте обработчик событий для обоих Button элементов управления Click события. Подробную информацию см. в разделе Практическое руководство. Создание обработчиков событий с помощью конструктора.
Перетащите Label управления из элементов на форму и переименуйте его
resultLabel
.Перетащите ProgressBar управления из элементов на форму.
Создание BackgroundWorker в форме
Можно создать BackgroundWorker для асинхронной операции с помощью Windows конструктора.
Создание BackgroundWorker с помощью конструктора
- Из компоненты вкладке элементов, перетащите BackgroundWorker на форму.
Добавление обработчиков асинхронных событий
Теперь вы готовы добавить обработчики событий для BackgroundWorker асинхронных событий компонента. Один из этих обработчиков вызывает длительную операцию, вычисляющую числа Фибоначчи в фоновом режиме.
Реализация обработчиков асинхронных событий
В свойства окне с BackgroundWorker компонент все еще выбран, щелкните события кнопки. Дважды щелкните DoWork и RunWorkerCompleted событий, чтобы создать обработчики событий. Дополнительные сведения об использовании обработчиков событий см. в разделе как: Создание обработчиков событий с помощью конструктора.
Создайте в форме новый метод с именем
ComputeFibonacci
. Этот метод выполняет фактическую работу и делает это в фоновом режиме. Данный код демонстрирует рекурсивную реализацию алгоритма Фибоначчи — она довольно неэффективна и занимает в разы больше времени при работе с большими числами. Он приводится в иллюстративных целях, чтобы показать, что операция может значительно замедлить работу вашего приложения.// This is the method that does the actual work. For this // example, it computes a Fibonacci number and // reports progress as it does its work. long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e) { // The parameter n must be >= 0 and <= 91. // Fib(n), with n > 91, overflows a long. if ((n < 0) || (n > 91)) { throw new ArgumentException( "value must be >= 0 and <= 91", "n"); } long result = 0; // Abort the operation if the user has canceled. // Note that a call to CancelAsync may have set // CancellationPending to true just after the // last invocation of this method exits, so this // code will not have the opportunity to set the // DoWorkEventArgs.Cancel flag to true. This means // that RunWorkerCompletedEventArgs.Cancelled will // not be set to true in your RunWorkerCompleted // event handler. This is a race condition. if (worker.CancellationPending) { e.Cancel = true; } else { if (n < 2) { result = 1; } else { result = ComputeFibonacci(n - 1, worker, e) + ComputeFibonacci(n - 2, worker, e); } // Report progress as a percentage of the total task. int percentComplete = (int)((float)n / (float)numberToCompute * 100); if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; worker.ReportProgress(percentComplete); } } return result; }
В DoWork обработчик событий, добавьте вызов
ComputeFibonacci
метод. Возьмите первый параметрComputeFibonacci
из Argument свойство DoWorkEventArgs. BackgroundWorker И DoWorkEventArgs параметры будут использоваться позже для отчетов о ходе выполнения и отмены поддержки. Присвойте возвращаемое значение изComputeFibonacci
для Result свойство DoWorkEventArgs. Этот результат будет доступен для RunWorkerCompleted обработчик событий.Note
DoWork Не ссылается на обработчик событий
backgroundWorker1
переменную экземпляра напрямую, так как это может привязать этот обработчик событий для определенного экземпляра BackgroundWorker. Вместо этого ссылка BackgroundWorker , создавший событие, берется изsender
параметра. Это важно, если в форме размещено несколько BackgroundWorker. Это также не следует выполнять операции все объекты пользовательского интерфейса в вашей DoWork обработчик событий. Вместо этого для взаимодействия в пользовательский интерфейс, через BackgroundWorker события.// This event handler is where the actual, // potentially time-consuming work is done. private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Get the BackgroundWorker that raised this event. BackgroundWorker worker = sender as BackgroundWorker; // Assign the result of the computation // to the Result property of the DoWorkEventArgs // object. This is will be available to the // RunWorkerCompleted eventhandler. e.Result = ComputeFibonacci((int)e.Argument, worker, e); }
В
startAsyncButton
элемента управления Click обработчик событий, добавьте код, который запускает асинхронную операцию.private void startAsyncButton_Click(System.Object sender, System.EventArgs e) { // Reset the text in the result label. resultLabel.Text = String.Empty; // Disable the UpDown control until // the asynchronous operation is done. this.numericUpDown1.Enabled = false; // Disable the Start button until // the asynchronous operation is done. this.startAsyncButton.Enabled = false; // Enable the Cancel button while // the asynchronous operation runs. this.cancelAsyncButton.Enabled = true; // Get the value from the UpDown control. numberToCompute = (int)numericUpDown1.Value; // Reset the variable for percentage tracking. highestPercentageReached = 0; // Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(numberToCompute); }
В RunWorkerCompleted обработчик событий, результат вычисления, которое необходимо присвоить
resultLabel
элемента управления.// This event handler deals with the results of the // background operation. private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { // First, handle the case where an exception was thrown. if (e.Error != null) { MessageBox.Show(e.Error.Message); } else if (e.Cancelled) { // Next, handle the case where the user canceled // the operation. // Note that due to a race condition in // the DoWork event handler, the Cancelled // flag may not have been set, even though // CancelAsync was called. resultLabel.Text = "Canceled"; } else { // Finally, handle the case where the operation // succeeded. resultLabel.Text = e.Result.ToString(); } // Enable the UpDown control. this.numericUpDown1.Enabled = true; // Enable the Start button. startAsyncButton.Enabled = true; // Disable the Cancel button. cancelAsyncButton.Enabled = false; }
Добавление отчетов о ходе выполнения и поддержка отмены
В случае асинхронных операций, занимающих долгое время, желательно сообщать пользователю о ходе выполнения, чтобы пользователь мог отменить операцию. BackgroundWorker Класс предоставляет событие, которое позволяет публиковать ход выполнения фоновой операции. Он также предоставляет флаг, позволяющий рабочему коду обнаружить вызов CancelAsync и прервать свое выполнение.
Реализация отчета о ходе выполнения
В окне Свойства выберите
backgroundWorker1
. Задайте для свойств WorkerReportsProgress и WorkerSupportsCancellation значениеtrue
.Объявите две переменные в форме
FibonacciCalculator
. Они будут использоваться для отслеживания хода выполнения.private int numberToCompute = 0; private int highestPercentageReached = 0;
Добавьте обработчик для события ProgressChanged. В ProgressChanged обработчик событий, обновите ProgressBar с ProgressPercentage свойство ProgressChangedEventArgs параметр.
// This event handler updates the progress bar. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { this.progressBar1.Value = e.ProgressPercentage; }
Реализация поддержки отмены
В
cancelAsyncButton
элемента управления Click обработчик событий, добавьте код, отменяющий асинхронную операцию.private void cancelAsyncButton_Click(System.Object sender, System.EventArgs e) { // Cancel the asynchronous operation. this.backgroundWorker1.CancelAsync(); // Disable the Cancel button. cancelAsyncButton.Enabled = false; }
Следующие фрагменты кода в методе
ComputeFibonacci
сообщают о ходе выполнения и поддерживают отмену.if (worker.CancellationPending) { e.Cancel = true; }
// Report progress as a percentage of the total task. int percentComplete = (int)((float)n / (float)numberToCompute * 100); if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; worker.ReportProgress(percentComplete); }
Контрольная точка
На этом этапе можно скомпилировать и запустить приложение калькулятора Фибоначчи.
Тестирование проекта
Чтобы скомпилировать и запустить приложение, нажмите клавишу F5.
Пока вычисление выполняется в фоновом режиме, вы увидите ProgressBar отображением хода выполнения вычислений. Операцию, ожидающую выполнения, можно отменить.
Если числа небольшие, вычисления выполняются быстро, а с крупными числами занимают заметно больше времени. Если ввести значение 30 или больше, задержка составит несколько секунд, в зависимости от скорости работы вашего компьютера. Для значений больше 40 вычисление может затянуться на несколько часов. Пока калькулятор вычисляет большое число Фибоначчи, форму можно свободно переместить, свернуть, развернуть и даже закрыть. Это связано с тем, что основной поток пользовательского интерфейса не дожидается, пока вычисление будет завершено.
Следующие шаги
Теперь, когда вы реализовали форму, которая использует BackgroundWorker компонент для вычислений в фоновом режиме, вы можете изучить другие возможности для асинхронных операций:
Используйте несколько BackgroundWorker объектов для нескольких одновременных операций.
Отладка многопоточных приложений, см. в разделе как: Использование окна потоков.
Реализация собственного компонента, поддерживающего модель асинхронного программирования. Дополнительные сведения см. в разделе Обзор асинхронной модели на основе событий.
Caution
При использовании любой многопоточности существует потенциальная возможность возникновения серьезных ошибок. Перед реализацией любого решения, в котором используется многопоточность, ознакомьтесь с разделом Рекомендации по работе с потоками.
См. также
- System.ComponentModel.BackgroundWorker
- Управляемая поточность
- Рекомендации по работе с потоками
- Обзор асинхронной модели, основанной на событиях
- Практическое руководство. Реализация формы, в которой выполняется фоновая операция
- Пошаговое руководство. Фоновое выполнение операции
- Компонент BackgroundWorker