BackgroundWorker 在執行DoWork事件時該如何取消呢?html
方法1 DoWork 執行一個(耗時)循環sql
方法2 DoWork執行一個(耗時)方法[注:方法沒有循環]數據庫
見代碼:編程
方法1中DoWork事件執行的是一個for循環(foreach,while.....)異步
取消操做很簡單,只要在循環中判斷便可異步編程
看代碼---------代碼是從網上拷貝下來的,這種例子網上不少post
#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事件中執行的是一個比較耗時的方法時該怎麼辦了.方法中沒有循環沒法判斷用戶是否執行了取消操做!this
那麼這裏就要用到[異步編程模式],在執行一個比較耗時的方法時,代碼還能繼續向下運行.....!spa
請看下面代碼-----------此代碼是本人本身寫的code
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); //能夠使用:delegate、Action、Func、predicate 等,具體可參考:C#委託的介紹(delegate、Action、Func、predicate) 和 委託的N種寫法 //開始異步執行(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; } } }
我這裏主要是方法2,在不少狀況下,咱們的DoWork事件都是執行一個方法,而不是一個循環....若是你也遇到要執行一個耗時方法,又要取消操做的話,請用方法2吧!