天天看點

C# 如何取消BackgroundWorker異步操作

BackgroundWorker 在執行DoWork事件時該如何取消呢?

方法1 DoWork 執行一個(耗時)循環

方法2 DoWork執行一個(耗時)方法[注:方法沒有循環]

見代碼:

方法1中DoWork事件執行的是一個for循環(foreach,while.....)

取消操作很簡單,隻要在循環中判斷即可

#region 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ComponentModel; 
using System.Threading; 
using System.Text.RegularExpressions; 
 
namespace ConsoleBackgroundworker 
{ 
  class Program 
  { 
    static BackgroundWorker bw; 
    static void Main() 
    { 
      bw = new BackgroundWorker(); 
      bw.WorkerReportsProgress = true; 
      bw.WorkerSupportsCancellation = true; 
      bw.DoWork += bw_DoWork; 
      bw.ProgressChanged += bw_ProgressChanged; 
      bw.RunWorkerCompleted += bw_RunWorkerCompleted; 
      bw.RunWorkerAsync("Hello to worker"); 
      Console.WriteLine("Press /"C/" to cancel"); 
 
      while (true) 
      { 
        //按C取消 
        if (Console.ReadKey(true).Key == ConsoleKey.C) 
        { 
          if (bw.IsBusy) 
            bw.CancelAsync(); //送出取消指令,但還未取消 
          else { break; } 
        } 
      } 
      //Console.ReadLine(); 
    } 
 
    static void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
      Console.WriteLine(e.Argument); 
      for (int i = 0; i <= 100; i += 1) 
      { 
        //判斷是否取消操作 
        if (bw.CancellationPending) 
        { 
          e.Cancel = true; //這裡才真正取消 
          return; 
        } 
        //傳遞給ProgressChanged 
        bw.ReportProgress(i); 
        Thread.Sleep(100); 
        e.Result = i; 
      } 
      // 最終傳遞給RunWorkerCopmleted  
    } 
 
    static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
      if (e.Cancelled) 
        Console.WriteLine("You cancelled!"); 
      else if (e.Error != null) 
        Console.WriteLine("Worker exception: " + e.Error.ToString()); 
      else 
      { 
        Console.WriteLine("Complete - " + e.Result);      // 從 DoWork  
      } 
    } 
 
    static void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
      Console.Write("{0,3}/b/b/b", e.ProgressPercentage); 
    } 
  } 
} 
#endregion 
           

方法2中DoWork事件中執行的是一個比較耗時的方法時該怎麼辦了.方法中沒有循環無法判斷使用者是否執行了取消操作!

那麼這裡就要用到[異步程式設計模式],在執行一個比較耗時的方法時,代碼還能繼續向下運作.....!

BackgroundWorker bgworker = new BackgroundWorker(); 
gworker.WorkerSupportsCancellation = true; //是否支援異步取消  如果要取消操作必須設定true 
     bgworker.DoWork += new DoWorkEventHandler(this.bgworker_DoWork); 
     bgworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.bgworker_RunWorkerCompleted); 
 
   private void begin_Click(object sender, EventArgs e) 
   { 
     //開始 
      if(!bgworker.IsBusy) 
       { 
           bgworker.RunWorkerAsync(); //開始操作 
        } 
   } 
 
   private void end_Click(object sender, EventArgs e) 
   { 
     //開始取消 
     if (bgworker.IsBusy) //是否在運作異步操作 
     { 
       bgworker.CancelAsync(); //(是)送出取消指令 
     } 
   } 
 
   private void bgworker_DoWork(object sender, DoWorkEventArgs e) 
   { 
     //Sql語句 查詢的資料很多 
     string sql = "select * from table";   
 
     //綁定委托要執行的方法 
     Del_DoWork work = new Del_DoWork(ReturnDataTable); 
 
     //開始異步執行(ReturnDataTable)方法 
     IAsyncResult ret = work.BeginInvoke(sql, null, null);  
      
     //(異步程式設計模式好久就是在執行一個很耗時的方法(ReturnDataTable)時,還能向下繼續運作代碼) 
 
     //接着運作下面的while循環, 
     //判斷異步操作是否完成 
     while (!ret.IsCompleted)   
     { 
       //沒完成 
       //判斷是否取消了backgroundworker異步操作 
       if (bgworker.CancellationPending)  
       { 
         //如何是  馬上取消backgroundwork操作(這個地方才是真正取消) 
         e.Cancel = true;  
         return; 
       } 
     } 
     e.Result = work.EndInvoke(ret); //傳回查詢結果 指派給e.Result 
   } 
 
   private delegate DataTable Del_DoWork(string sql);  //建立一個委托 
   /// <summary> 
   /// 查詢資料庫表--------一個很耗時的方法 
   /// </summary> 
   /// <param name="sql"></param> 
   /// <returns></returns> 
   private DataTable ReturnDataTable(string sql) 
   { 
     DataTable table = new DataTable(); 
     SqlConnection conn = new SqlConnection("Server............"); 
     //.....................(省略) 
     return table; 
   } 
 
   private void bgworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
   { 
     if (e.Cancelled) 
     { 
       MessageBox.Show("您取消了操作!"); 
     } 
     else if (e.Error != null) 
     { 
       MessageBox.Show("出現錯誤!"); 
     } 
     else 
     { 
       DataTable table = e.Result as DataTable; 
       if (table != null) 
       { 
         //得到資料,進行顯示操作 
         //dataGridView1.DataSource = table; 
       } 
     } 
   }