2017-08-21 113 views
2

我正在使用WinForm,從中我需要的所有進程都被引導。現在我試圖將BackgroundWorkerProgressBar以及取消按鈕集成到我的代碼中。我希望它在本地代碼周圍,而不是單獨的方法。爲了測試這個,一個新的表單用一個進度條(不活動)和一個停止for循環的按鈕來創建。但是,代碼無法正常工作(甚至還沒有包含進度條)。表單立即凍結(見圖),所以我無法測試取消按鈕。然而,for循環被執行並顯示"Done: " + l.ToString()。我該如何解決這個問題?使用BackgroundWorker凍結表格

void stopMeasurement(object sender, EventArgs e) 
{ 
    stopMeas = true;  
} 

public void testcancel() // Test method which is triggered manually 
{ 
    int l = 0; 

    MetingProgress metingProgress = new MetingProgress(); 
    metingProgress.btnCancelmeting.Click += new EventHandler(stopMeasurement); 

    BackgroundWorker worker = new BackgroundWorker(); 
    worker.WorkerSupportsCancellation = true; 
    worker.DoWork += (sender, args) => 
    {      
     for (int k = 0; k < 10; k++) 
     { 
      Thread.Sleep(1000); 
      l++; 

      if (worker.CancellationPending) 
       break; 
     } 

     MessageBox.Show("Done: " + l.ToString()); 

    }; 
    worker.RunWorkerAsync(); 

    while (worker.IsBusy) 
    { 
     if (stopMeas) 
      worker.CancelAsync(); 
    } 

    metingProgress.Dispose(); 
    MessageBox.Show("All done"); 

} 

enter image description here

+0

是的,我已經有我的代碼需要進入背景工作的幾個任務,所以我想在我的例子中有一個設置。 for-loop類似於要完成的任務。 – 10a

+0

好的我明白了,那麼'testcancel'實際上是一種簡單地觸發線程並讓它在後臺運行的方法,而這實際上都是要做的。由於線程運行時間較長,因此您不應該嘗試處理這種方法中的表單處理!這將是線程方法的工作。也是'MessageBox.Show(「All done」);'line屬於'DoWork'事件,因爲實際上只有線程本身知道作業何時完成,而不是啓動線程的方法 –

回答

4

的形式凍結立即

這是因爲你有一個while循環在主線程仍在運行!所以表單不會響應。這叫做buisy等待。您將無法撥打CancelAsync方法。

一種解決方案可能是除去while循環並把取消呼叫到按鈕事件代碼:

void stopMeasurement(object sender, EventArgs e) 
{ 
    stopMeas = true; 
    worker.CancelAsync(); 

} 

什麼你已經基本上完成了是:你創建了第二個取消令牌。因此,另一種可能性是隻使用stopMeas取消後臺操作:

worker.DoWork += (sender, args) => 
{      
    for (int k = 0; k < 10; k++) 
    { 
     Thread.Sleep(1000); 
     l++; 

     if (stopMeas) 
      break; 
    } 

    string mes = stopMeas ? "Done: " + l.ToString() : "Task aborted!"; 
    MessageBox.Show(mes); 

}; 

編輯:也是這一行:

metingProgress.Dispose(); 

可能導致ObjectDisposed例外。如果後臺進程仍在運行並嘗試更新進度條,並且您已經處理該表單。你應該刪除這行,並把它留給垃圾收集器。

+0

刪除循環?但是工人內部什麼都沒有留下來? – 10a

+0

他在說'while(worker.IsBusy)'循環。 – Fildor

+0

是的,我剛剛看到它,現在它正在工作。 – 10a

4

此代碼是你的問題:

while (worker.IsBusy) 
{ 
    if (stopMeas) 
     worker.CancelAsync(); 
} 

您的GUI線程是在循環,直到你的工人完成。 您需要使EventHandler內的工作者實例可以訪問,並從那裏調用worker.CancelAsync()。


這個之外,我個人會提高代碼的2個步驟:

  1. 移動整個的BackgroundWorker到MetingProgress類,使它的構造採取委託實際工作落實。

  2. 使用TAP(任務異步模式),即異步/等待Task with Progress和CancellationToken。

+0

我正在嘗試擴展我的代碼一步一步,並瞭解它是如何工作的,所以我可能會最終得到一些建議。 – 10a

+2

過渡到TAP真的需要一些時間來包裝你的頭。慢慢來,但絕對值得一試。一步一步做,是你可以做的最好的學習。祝你好運! – Fildor