C#使用BackgroundWorker控件
在我們的程序中,經(jīng)常會有一些耗時較長的運算,為了保證用戶體驗,不引起界面不響應(yīng),我們一般會采用多線程操作,讓耗時操作在后臺完成,完成后再進行處理或給出提示,在運行中,也會時時去刷新界面上的進度條等顯示,必要時還要控制后臺線程中斷當前操作。
在.net中,提供了一個組件BackgroundWorker就是專門解決這個問題的。BackgroundWorker類允許在單獨的專用線程上運行操作。 耗時的操作(如下載和數(shù)據(jù)庫事務(wù))在長時間運行時可能會導(dǎo)致用戶界面(UI)似乎處于停止響應(yīng)狀態(tài)。如果需要能進行響應(yīng)的用戶界面,而且面臨與這類操作相關(guān)的長時間延遲,則可以使用BackgroundWorker類方便地解決問題。
程序執(zhí)行步驟:
- 1、調(diào)用BackgroundWorker的RunWorkerAsync()方法,如果后臺操作需要參數(shù),在調(diào)用RunWorkerAsync()方法時給出參數(shù),在DoWork事件處理程序內(nèi)部,可以從DoWorkEventArgs.Argument屬性中提取該參數(shù)。
- 2、執(zhí)行DoWork事件,后臺需要執(zhí)行的代碼放到DoWork事件里面執(zhí)行。當調(diào)用RunWorkerAsync()方法時,BackgroundWorker通過觸發(fā)DoWork事件,開始執(zhí)行后臺操作
顯示后臺操作進度:
為了顯示后臺操作的執(zhí)行進度,首先要使WorkerReportsProgress等于true,然后調(diào)用BackgroundWorker的ReportProgress()方法,通過它傳遞操作完成的進度值,此外,該方法觸發(fā)ProgressChanged事件,在此事件中,通過ProgressChangedEventArgs的實例,接收到主線程傳遞過來的參數(shù)。
取消后臺操作:
為了使 BackgroundWorker 可以取消后臺正在執(zhí)行的操作,首先要把屬性WorkerSupportsCancellation 的值設(shè)置為 true。接著調(diào)用CancelAsync()方法,該方法使得屬性CancellationPending 為true,利用CancellationPending 屬性,可以判斷是否取消后臺異步操作。
后臺操作完成后,反饋給用戶:
當后臺操作完成以后,無論是completed 還是cancelled,RunWorkerCompleted()事件都會被觸發(fā),通過此方法可以將后臺操作的完成結(jié)果反饋給用戶。RunWorkerCompleted 事件處理函數(shù)會在DoWork 事件處理函數(shù)返回后被調(diào)用。通過它我們可以進行一些運算結(jié)束后的操作,比如禁用取消按鈕,異常處理,結(jié)果顯示等。注意,如果想要拿到e.Result,您需要在BGWorker_DoWork方法中設(shè)置 e.Result屬性另外,通過RunWorkerCompletedEventArgs實例的Cancelled 屬性,以判斷是否是Cancel操作使得后臺操作終止;
從后臺操作返回值
在執(zhí)行DoWork事件時DoWorkEventArgs實例的Result屬性,返回值到用戶;在RunWorkerCompleted事件里,RunWorkerCompletedEventArgs 實例的Result屬性接收值;
創(chuàng)建BackgroundWorkerDemo例子:
- 1.新建一個windows窗體應(yīng)用程序,如: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
{
//設(shè)置生成臨時文件的路徑
static string strSaveDir = @"F:\培訓";
public FrmDemo()
{
InitializeComponent();
//顯示后臺操作的執(zhí)行進度
this.bgWork.WorkerReportsProgress = true;
//可以取消后臺正在執(zhí)行的操作
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());
//設(shè)置進度條
this.proBar.Minimum = 0;
this.proBar.Maximum = count;
this.proBar.Value = this.proBar.Minimum;
//開始執(zhí)行異步線程,進行后臺操作,給后臺傳遞參數(shù)
this.bgWork.RunWorkerAsync(count);
}
/// <summary>
/// 后臺操作要處理的任務(wù)代碼
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void bgWork_DoWork(object sender, DoWorkEventArgs e)
{
//獲取從RunWorkerAsync()方法里面?zhèn)鬟f的參數(shù)的值
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;
}
//設(shè)置返回值
e.Result = 234;
}
}
/// <summary>
/// 更新前臺界面進度條
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void bgWork_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//獲取異步任務(wù)的進度百分百
int val = e.ProgressPercentage;
this.label2.Text = string.Format("已經(jīng)生成{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)
{
//調(diào)用CancelAsync(),取消掛起的后臺操作
this.bgWork.CancelAsync();
}
}
}運行界面:

操作完成界面:

接收返回值:

取消后臺操作:

到此這篇關(guān)于C#使用BackgroundWorker控件的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
用C#的params關(guān)鍵字實現(xiàn)方法形參個數(shù)可變示例
params關(guān)鍵字以實現(xiàn)方法形參個數(shù)可變是C#語法的一大優(yōu)點,下面是用C#中的params關(guān)鍵字實現(xiàn)方法形參個數(shù)可變2014-09-09
C# Record構(gòu)造函數(shù)的行為更改詳解
C# 9 中的record類型是僅具有只讀屬性的輕量級、不可變數(shù)據(jù)類型(或輕量級類),下面這篇文章主要給大家介紹了關(guān)于C# Record構(gòu)造函數(shù)的行為更改的相關(guān)資料,需要的朋友可以參考下2021-08-08
C# 繪制統(tǒng)計圖大全(柱狀圖, 折線圖, 扇形圖)
本篇文章介紹了C# 繪制統(tǒng)計圖大全,其中包括狀圖, 折線圖, 扇形圖,有需要的同學可以了解一下。2016-11-11
C#實現(xiàn)Excel動態(tài)生成PivotTable
這篇文章主要為大家詳細介紹了C#實現(xiàn)Excel動態(tài)生成PivotTable的相關(guān)方法,感興趣的小伙伴們可以參考一下2016-04-04

