邊學習邊分享,純屬拋磚引玉。異步
線程的一個好處是異步的執行操做,在winform中,不少耗時操做執行時,爲優化用戶體驗,避免長時間等待,從而運用線程技術異步的執行耗時操做,但不會阻塞主線程。學習
最近系統不少耗時查詢致使體驗不好,因而想到了用BackGroundWorker異步處理。並且要支持某些耗時達到幾十秒的操做,能夠取消。優化
BackGroundWorker有CancelAsync()這個方法。該方法只會將BackGroundWorker的CancellationPending屬性設爲true,但不會實際終止線程!網上找了些資料,代碼以下this
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { for (int i = 0; i < 100; i++) { if (backgroundWorker1.CancellationPending) { e.Cancel = true; return; } } }
即在doWork事件中,不停的循環判斷是否執行了取消操做。這種適用於執行屢次方法時,並且沒法在某個方法執行時將線程取消。若是我doWork事件裏,沒有for循環,而是一次耗時的數據訪問操做,那這樣的處理沒有任何意義。spa
因而在下想到,能夠在doWork事件裏作以下處理線程
1.異步的去執行耗時操做。code
2.while監視異步耗時操做是否完成,只要未完成就一直循環。循環內部判斷是否執行了取消操做。若是執行了取消操做,則終止線程。代碼以下orm
private delegate int LongTimeDele(); private bool isComplated=false; private int result=0; private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { this.BeginInvoke(new LongTimeDele(()=>{ Thread.Sleep(10000);////模擬耗時 for (int i = 0; i < 100; i++) { result++; } isComplated=true; })); while(!isComplated){ if (backgroundWorker1.CancellationPending) { e.Cancel = true; return; } } }
試驗以後,不知何故在this.BeginInvoke中的循環會阻塞主線程! 即界面卡主不動了,BeginInvoke應該是一步執行的,在下功力尚淺,不知何故,還請高手指教。blog
因而想到了異步委託。直接上代碼事件
cs代碼
public partial class BackgroundWorkerTest : Form { public BackgroundWorkerTest() { InitializeComponent(); } /// <summary> /// 創建一個委託,用來調用耗時操做。返回值是int,固然也能夠是string、DataTable..... /// </summary> /// <returns></returns> private delegate int LongTimeDele(); /// <summary> /// doWork事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { //聲明一個委託的實例 var waitHandller = new LongTimeDele( () => { //線程休眠10秒,模擬耗時操做 Thread.Sleep(10000); var sumResult = 0; for (int i = 0; i < 100; i++) { sumResult++; } return sumResult; }); //BeginInvoke,異步的去執行委託實例裏的匿名方法。該方法返回的是一個IAsyncResult。返回值的狀態會實時更新! var isa = waitHandller.BeginInvoke(null, null); //因爲上面是異步,因此while的代碼不會等待上面操做完成後執行,兩者幾乎同時執行 //判斷isa是否完成了,未完成的話(等待耗時操做)執行內部代碼 while (!isa.IsCompleted) { //判斷CancellationPending屬性是否爲true。若是你點擊了取消button,這個屬性就變成true了 if (backgroundWorker1.CancellationPending) { //取消操做 e.Cancel = true; return; } } //能執行到這裏就說明操做完成了,把結果放進e中,傳遞給RunWorkerCompleted事件 e.Result = waitHandller.EndInvoke(isa); } /// <summary> /// backgroundWorker執行完畢時事件,不管正常完成仍是取消都會出發該事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //只要不是類型EventArgs,你想要的數據e裏面應有盡有!判斷是否取消了操做 if (e.Cancelled) { MessageBox.Show("操做已取消"); return; } //不然顯示結果 MessageBox.Show(e.Result.ToString()); } /// <summary> /// 取消按鈕事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnCancle_Click(object sender, EventArgs e) { //調用 backgroundWorker的CancelAsync()方法,該方法只會將CancellationPending屬性設爲true,並不會實際結束線程執行 backgroundWorker1.CancelAsync(); } /// <summary> /// 開始按鈕事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStart_Click(object sender, EventArgs e) { //判斷線程是否繁忙 if (backgroundWorker1.IsBusy) { MessageBox.Show("系統繁忙"); return; } //空閒開始異步操做 backgroundWorker1.RunWorkerAsync(); } }