2014-11-24 51 views
2

我使用一個BackgroundWorker在我的WinForms應用程序來執行發生在另一個類(執行數據庫操作)長時間運行的任務。由於所有的工作都是在另一個班級完成的,取消並不是那麼簡單。我正在使用其他課程中的事件(GenerateStats)在後臺操作完成時更新進度。我想通過取消操作來做類似的事情。我不能只叫cancellationPending在DoWork的功能,因爲該方法將永遠看不到它,直到它完成和失敗的目的。我希望取消功能不需要將BackgroundWorker傳遞給generateForSubject()。反正是有,這可以支持從generateForSubject()方法消除在GenerateStats類。這是類的實例化的操作執行中:的BackgroundWorker取消

GenerateStats genStats = new GenerateStats(); 

這是我的DoWork函數,該函數調用ReportProgress方法隨時在其他類的事件被調用。它還調用執行操作的其他類generateForSubject()的方法。

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    BackgroundWorker worker = sender as BackgroundWorker; 

    genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState); 
    genStats.generateForSubject(); 
} 

這是按鈕單擊事件處理程序,應啓動撤銷和運行CancelAsync()

private void btnStop_Click(object sender, EventArgs e) 
{ 
    if (backgroundWorker.IsBusy) 
    { 
     backgroundWorker.CancelAsync(); 
    } 
} 

這是我獨立的類執行該操作,以創建ProgressChanged事件處理一起,所以我的班能更新了有關進展情況的表格。如果取消可以類似地執行,那將是非常棒的。

public event ProgressChangedEventHandler ProgressChanged; 

protected virtual void OnProgressChanged(int progress, string message) 
{ 
    if (ProgressChanged != null) 
    { 
     ProgressChanged(this, new ProgressChangedEventArgs(progress, message)); 
    } 
} 

public void generateForSubject() 
{ 
    //Perform db operation not important, but it takes time 

    OnProgressChanged(33, "Finished 1st set of stats"); 
    //I hope to check for cancellation here 

    //Perform db operation not important, but it takes time 

    OnProgressChanged(66, "Finished 2nd set of stats"); 
    //I hope to check for cancellation here   

    //Perform db operation not important, but it takes time 

    OnProgressChanged(99, "Finished 3rd set of stats"); 
    //I hope to check for cancellation here 
} 

只是爲了澄清,如果有任何不確定性是什麼我問,有沒有什麼辦法,我支持我在其他類的BackgroundWorker取消,而沒有經過的BackgroundWorker的方法。如果是絕對沒有辦法,我要的話,我會通過的BackgroundWorker

回答

3

如果您可以更具體地說明您不願意通過BackgroundWorker實例,那將會很有幫助。瞭解爲什麼這是設計要求可以幫助您更好地回答您的問題。

也就是說,您可以將相同的原則應用於ProgressChanged事件並委派取消檢查。例如:

class GenerateStats 
{ 
    public event EventHandler<CancelEventArgs> CheckCancel; 

    private bool OnCheckCancel() 
    { 
     EventHandler<CancelEventArgs> handler = CheckCancel; 

     if (handler != null) 
     { 
      CancelEventArgs e = new CancelEventArgs(); 

      handler(this, e); 

      return e.Cancel; 
     } 

     return false; 
    } 

    public void generateForSubject() 
    { 
     //Perform db operation not important, but it takes time 

     OnProgressChanged(33, "Finished 1st set of stats"); 
     if (OnCheckCancel()) 
     { 
      // Or other cancellation logic here 
      return; 
     } 

     //Perform db operation not important, but it takes time 

     OnProgressChanged(66, "Finished 2nd set of stats"); 
     if (OnCheckCancel()) 
     { 
      // Or other cancellation logic here 
      return; 
     } 

     //Perform db operation not important, but it takes time 

     OnProgressChanged(99, "Finished 3rd set of stats"); 
     if (OnCheckCancel()) 
     { 
      // Or other cancellation logic here 
      return; 
     } 
    } 
} 

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    BackgroundWorker worker = sender as BackgroundWorker; 

    genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState); 
    genStats.CheckCancel += (sender1, e1) => e1.Cancel = worker.CancellationPending; 
    genStats.generateForSubject(); 
} 

這使得GenerateStats類檢查正待取消,而無需將BackgroundWorker實例的直接訪問,就像ProgressChanged事件允許其報告通過BackgroundWorker進度,避免直接訪問BackgroundWorker

0

你的方法應該定期檢查CancellationPending屬性,看是否請求被註銷製作。然後決定取消操作。請參閱MSDN link

從MSDN:

請注意,您在DoWork的事件處理程序代碼可以完成其 工作作爲取消請求正在取得,和您的查詢循環 可能會錯過CancellationPending被設置爲true。在這種情況下,您的RunWorkerCompleted事件處理程序中的System.ComponentModel.RunWorkerCompletedEventArgs的 已取消標誌將不會設置爲true,即使是 也會發出取消請求。這種情況被稱爲 競態條件是多線程編程中普遍關注的問題。 有關多線程設計問題的更多信息,請參閱受管理的 線程最佳實踐。

編輯:

如果您不希望BackgroundWorker的傳遞給generateForSubject方法。收到CancelAsync時,在類中設置一個屬性。在每次操作之前從generateForSubject方法檢查此屬性的值。

+0

該方法如何知道任何有關CancellationPending而不傳遞backgroundWorker? – frontin 2014-11-24 05:13:32

+0

那是什麼。你需要在generateForSubject方法中有這個。並且在每個主要操作之前檢查它。這是我所知道的。 – 2014-11-24 05:14:50

+0

由於OP不希望傳遞後臺工作,所以不會工作。 – prem 2014-11-24 05:16:47