BackgroundWorker В C#
В случае выполнения трудоемких задач (например, чтение очень большого текстового файла), может случиться так, что форма застынет, так сказать. Это происходит потому, что все работает в одном потоке, и поэтому форма не имеет возможности реагировать на ввод пользователя или перерисовывать. Самый простой способ имитировать такое поведение-это установить поток.Спящий режим (10000) (ранее с помощью системы. Threading .) Это позволит заморозить форму в течение 10 секунд.
Чтобы предотвратить это замораживание, существует пространство имен threading. Существует множество способов создания большего количества потоков (многопоточность). Чтобы упростить этот сложный раздел потоковой обработки, .NET представил BackgroundWorker. Я хотел бы показать вам это на примере.
Создайте проект Windows Forms, добавьте в него кнопку (btnStartEnd) и панель прогресса (progressBar1) и переключитесь в представление кода.
Здесь мы сначала добавим использование.
1 |
using System.Threading; |
Мы создаем упомянутый фоновый работник глобально в классе Form1
Глобальная переменная BackgroundWorker
1 |
BackgroundWorker worker; |
Событие Form Load
1 2 3 4 5 6 7 8 9 10 11 12 |
private void Form1_Load(object sender, EventArgs e) { worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = true; worker.DoWork += new DoWorkEventHandler(worker_DoWork); worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); } |
В событии загрузки формы мы сначала создаем новый экземпляр фонового рабочего объекта и устанавливаем свойства WorkerReportsProgress и WorkerSupportsCancellation в значение true.
WorkerReportsProgress: необходимо, пока BackgroundWorker занят, передавать статусы в форму для указания хода выполнения.
WorkerSupportsCancellation: так что мы можем отменить обработку в BackgroundWorker в любое время.
Затем мы регистрируем необходимые события фонового работника, чтобы реагировать на каждый инцидент.
DoWork Event of the BackgroundWorker
1 2 3 4 5 6 7 8 9 10 11 |
void worker_DoWork(object sender, DoWorkEventArgs e) { int percentFinished = (int)e.Argument; while (!worker.CancellationPending && percentFinished < 100) { percentFinished++; worker.ReportProgress(percentFinished); System.Threading.Thread.Sleep(50); } e.Result = percentFinished; } |
В DoWork-событии теперь появляется трудоемкая часть кода, в которой форма будет замораживаться в обычном случае.
Следует отметить, что в этом случае не UserControls могут быть доступны, так как нам не разрешено передавать значения перекрестного потока (если мы не используем Invoke).
В этом случае мы сначала назначаем процентное значение, если работник был остановлен и теперь задача должна быть продолжена.
Затем мы создаем цикл while, который выполняется до тех пор, пока не будет достигнуто 100% или поток не будет остановлен с помощью функции CancelAsynch(). В цикле while мы увеличиваем состояние% и сообщаем фоновому работнику, что что-то изменилось, вызвав метод ReportProgress. Чтобы нить не закончилась слишком быстро и для лучшего обзора, у меня есть нить.Установлен режим ожидания в 50 миллисекунд. В конце события DoWork мы даем текущий процент в результате.
ProgressChanged событие backgroundworker
1 2 3 4 |
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage;//www.csharp-console-examples.com } |
Событие ProgressChanged вызывается всякий раз, когда вызывается метод ReportProgress() BackgroundWorker (используется в верхней части события DoWork).
Все, что мы делаем здесь, чтобы обновить значение ProgressBar. Мы получаем текущий процент от ProgressChangedEventArgs.
RunWorkerCompleted событие BackgroundWorker
1 2 3 4 5 6 |
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { MessageBox.Show("Asynchronous thread came up to the value:" + e.Result.ToString()); btnStartEnd.Text = "Start"; } |
Как следует из названия события, RunWorkerCompleted событие вызывается, как только backgroundworker завершает свою задачу. Он не делает различия, была ли обработка теперь запущена до конца или код был прерван, установив CancelAsync().
В MessageBox мы теперь покажем, на сколько% BackgroundWorker прибыл и дать кнопку текст “начать” снова, чтобы позволить Backgroundworker либо перезапустить или продолжить работу.
Теперь только обработка кнопки отсутствует.
Нажмите событие кнопки
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
private void btnStartEnd_Click(object sender, EventArgs e) { if (worker.IsBusy) { worker.CancelAsync(); btnStartEnd.Text = "Start"; } else //www.csharp-console-examples.com { if (progressBar1.Value == progressBar1.Maximum) { progressBar1.Value = progressBar1.Minimum; } worker.RunWorkerAsync(progressBar1.Value); btnStartEnd.Text = "Stop"; } } |
Если BackgroundWorker занят, его следует остановить с помощью функции CancelAsync(). Это внутренне устанавливает флаг CancellationPending в true. Кроме того, мы возвращаем ButtonText при запуске, если хотим, чтобы BackgroundWorker работал.
Если BackgroundWorker не занят, проверьте, имеет ли Progressbar уже максимальное значение в то время. Если это применимо, мы устанавливаем его обратно к минимальному значению.
Несмотря на это, BackgroundWorker запускается с помощью RundWorkerAsync(). В качестве параметра мы передаем текущее значение ProgressBar. Текст кнопки мы все еще устанавливаем для остановки, если пользователь хочет отменить BackgroundWorker.