首頁 > 軟體

C#使用BackgroundWorker控制元件

2022-02-24 13:00:35

在我們的程式中,經常會有一些耗時較長的運算,為了保證使用者體驗,不引起介面不響應,我們一般會採用多執行緒操作,讓耗時操作在後臺完成,完成後再進行處理或給出提示,在執行中,也會時時去重新整理介面上的進度條等顯示,必要時還要控制後臺執行緒中斷當前操作。

在.net中,提供了一個元件BackgroundWorker就是專門解決這個問題的。BackgroundWorker類允許在單獨的專用執行緒上執行操作。 耗時的操作(如下載和資料庫事務)在長時間執行時可能會導致使用者介面(UI)似乎處於停止響應狀態。如果需要能進行響應的使用者介面,而且面臨與這類操作相關的長時間延遲,則可以使用BackgroundWorker類方便地解決問題。

程式執行步驟:

  • 1、呼叫BackgroundWorker的RunWorkerAsync()方法,如果後臺操作需要引數,在呼叫RunWorkerAsync()方法時給出引數,在DoWork事件處理程式內部,可以從DoWorkEventArgs.Argument屬性中提取該引數。
  • 2、執行DoWork事件,後臺需要執行的程式碼放到DoWork事件裡面執行。當呼叫RunWorkerAsync()方法時,BackgroundWorker通過觸發DoWork事件,開始執行後臺操作

顯示後臺操作進度:

為了顯示後臺操作的執行進度,首先要使WorkerReportsProgress等於true,然後呼叫BackgroundWorker的ReportProgress()方法,通過它傳遞操作完成的進度值,此外,該方法觸發ProgressChanged事件,在此事件中,通過ProgressChangedEventArgs的範例,接收到主執行緒傳遞過來的引數。

取消後臺操作:

為了使 BackgroundWorker 可以取消後臺正在執行的操作,首先要把屬性WorkerSupportsCancellation 的值設定為 true。接著呼叫CancelAsync()方法,該方法使得屬性CancellationPending 為true,利用CancellationPending 屬性,可以判斷是否取消後臺非同步操作。

後臺操作完成後,反饋給使用者:

當後臺操作完成以後,無論是completed 還是cancelled,RunWorkerCompleted()事件都會被觸發,通過此方法可以將後臺操作的完成結果反饋給使用者。RunWorkerCompleted 事件處理常式會在DoWork 事件處理常式返回後被呼叫。通過它我們可以進行一些運算結束後的操作,比如禁用取消按鈕,例外處理,結果顯示等。注意,如果想要拿到e.Result,您需要在BGWorker_DoWork方法中設定 e.Result屬性另外,通過RunWorkerCompletedEventArgs範例的Cancelled 屬性,以判斷是否是Cancel操作使得後臺操作終止;

從後臺操作返回值

在執行DoWork事件時DoWorkEventArgs範例的Result屬性,返回值到使用者;在RunWorkerCompleted事件裡,RunWorkerCompletedEventArgs 範例的Result屬性接收值;

建立BackgroundWorkerDemo例子:

  • 1.新建一個windows表單應用程式,如:BackgroundWorkerDemo
  • 2.拖一個ProgressBar(進度條)和一個BackgroundWorker控制元件到Form表單上,介面如圖:

後臺程式碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Threading;

namespace BackgroundWorkerDemo
{
    public partial class FrmDemo : Form
    {
        //設定生成臨時檔案的路徑
        static string strSaveDir = @"F:培訓";
        public FrmDemo()
        {
            InitializeComponent();

            //顯示後臺操作的執行進度
            this.bgWork.WorkerReportsProgress = true;
            //可以取消後臺正在執行的操作
            this.bgWork.WorkerSupportsCancellation = true;
        }

        /// <summary>
        /// 開始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Start_Click(object sender, EventArgs e)
        {
            if (Directory.Exists(strSaveDir) == false)
            {
                return;
            }
            btn_Start.Enabled = false;
            int count = Convert.ToInt32(this.txt_File.Text.ToString().Trim());
            //設定進度條
            this.proBar.Minimum = 0;
            this.proBar.Maximum = count;
            this.proBar.Value = this.proBar.Minimum;
            //開始執行非同步執行緒,進行後臺操作,給後臺傳遞引數
            this.bgWork.RunWorkerAsync(count);
        }

        /// <summary>
        /// 後臺操作要處理的任務程式碼
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWork_DoWork(object sender, DoWorkEventArgs e)
        {
            //獲取從RunWorkerAsync()方法裡面傳遞的引數的值
            int fileCount= Convert.ToInt32(e.Argument);
            Random rand = new Random();
            byte[] buffer = new byte[2048];
            for (int i = 0; i < fileCount; i++)
            {
                try
                {
                    string strFileName = Path.Combine(strSaveDir, i.ToString() + ".tmp");
                    using (var stream = File.Create(strFileName))
                    {
                        int n = 0;
                        int maxByte = 8 * 1024 * 1024;
                        while (n < maxByte)
                        {
                            rand.NextBytes(buffer);
                            stream.Write(buffer, 0, buffer.Length);
                            n += buffer.Length;
                        }
                    }
                }
                catch (Exception ex)
                {
                    continue;
                }
                finally
                {
                    //報告進度
                    this.bgWork.ReportProgress(i + 1);
                    Thread.Sleep(100);
                }

                //判斷是否取消了後臺操作
                if (bgWork.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                //設定返回值
                e.Result = 234;
            }
        }

        /// <summary>
        /// 更新前臺介面進度條
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWork_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //獲取非同步任務的進度百分百
            int val = e.ProgressPercentage;
            this.label2.Text = string.Format("已經生成{0}個檔案", val);
            //進度條顯示當前進度
            this.proBar.Value = val;
        }

        /// <summary>
        /// 後臺操作完成,向前臺反饋資訊
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWork_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            btn_Start.Enabled = true;
            //使用者取消操作(e.Cancelled==true,表示非同步操作已被取消)
            if (e.Cancelled)
            {
                MessageBox.Show("使用者取消後臺操作", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                MessageBox.Show("操作完成", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

                //接收返回值
                int result = (int)e.Result;

                MessageBox.Show("返回值:" + result);
            }
        }

        /// <summary>
        /// 取消
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Cancle_Click(object sender, EventArgs e)
        {
            //呼叫CancelAsync(),取消掛起的後臺操作
            this.bgWork.CancelAsync();
        }
    }
}

執行介面:

操作完成介面:

接收返回值:

取消後臺操作:

 到此這篇關於C#使用BackgroundWorker控制元件的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com