2009-05-05 86 views
4

C#2008C#取消後臺工作

我使用下面的代碼登錄到一個軟電話的DoWork的。但是,登錄過程是一個漫長的過程,因爲有很多事情必須進行初始化和檢查,我只在這裏放了一些,因爲它會使代碼長時間發佈。

在下面的代碼中,我檢查CancellationPending是否在取消按鈕單擊事件中調用了CancelAsync,然後再執行每次檢查。它是否正確?此外,如果檢查失敗,我還會調用CancelAsync並將e.Cancel設置爲true。

我想知道我的方法,我在這裏使用的是最好的方法來使用。

非常感謝任何建議,

private void bgwProcessLogin_DoWork(object sender, DoWorkEventArgs e) 
    { 
     /* 
     * Perform at test to see if the background worker has been 
     * cancelled by the user before attemping to continue to login. 
     * 
     * Cancel background worker on any failed attemp to login 
     */ 

     // Start with cancel being false as to reset this if cancel has been set to true 
     // in the cancel button. 
     e.Cancel = false; 

     NetworkingTest connection_test = new NetworkingTest(); 
     if (!this.bgwProcessLogin.CancellationPending) 
     { 
      // Check local LAN or Wireless connection    
      if (!connection_test.IsNetworkConnected()) 
      { 
       // Update label 
       if (this.lblRegistering.InvokeRequired) 
       { 
        this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(UpdateRegisterLabel), "No network connection"); 
       } 
       else 
       { 
        this.lblRegistering.Text = "No network connection"; 
       } 
       // Failed attemp 
       this.bgwProcessLogin.CancelAsync(); 
       e.Cancel = true; 
       return; 
      } 
      // Report current progress 
      this.bgwProcessLogin.ReportProgress(0, "Network connected"); 
     } 
     else 
     { 
      // User cancelled 
      e.Cancel = true; 
      return; 
     } 

     // Test if access to Server is available 
     if (!this.bgwProcessLogin.CancellationPending) 
     { 
      if (!connection_test.IsSIPServerAvailable()) 
      { 
       // Update label 
       if (this.lblRegistering.InvokeRequired) 
       { 
        this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(UpdateRegisterLabel), "Server unavailable"); 
       } 
       else 
       { 
        this.lblRegistering.Text = "Server unavailable"; 
       } 
       // Failed attemp 
       this.bgwProcessLogin.CancelAsync(); 
       e.Cancel = true; 
       return; 
      } 
      // Report current progress 
      this.bgwProcessLogin.ReportProgress(1, "Server available"); 
     } 
     else 
     { 
      // User cancelled 
      e.Cancel = true; 
      return; 
     } 
     . 
     . 
     . 
} 


private void bgwProcessLogin_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     // Check for any errors 
     if (e.Error == null) 
     { 
      if (e.Cancelled) 
      { 
       // User cancelled login or login failed     
      } 
      else 
      { 
       // Login completed successfully     
      } 
     } 
     else 
     { 
      // Something failed display error 
      this.statusDisplay1.CallStatus = e.Error.Message; 
     } 
    } 


private void bgwProcessLogin_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     this.lblRegistering.Text = e.UserState.ToString(); 
    } 

private void btnCancel_Click(object sender, EventArgs e) 
    { 
     // Cancel the logging in process 
     this.bgwProcessLogin.CancelAsync(); 
     this.lblRegistering.Text = "Logged out"; 
} 

回答

8

可能只有一個問題:如果DoWork事件處理程序中的某個操作會持續很長時間。在這種情況下,您可以在操作完成後中止待處理操作。如果DoWork事件中的所有操作都不能持續很長時間(例如,不超過5秒),那麼它的一切正常,但如果其中一項操作可以持續很長時間(例如5分鐘),則在這種情況下,用戶有等到這個操作完成。

如果DoWork包含持久的操作,您可以使用AbortableBackgroundWorker之類的東西。事情是這樣的:

public class AbortableBackgroundWorker : BackgroundWorker 
{ 
    private Thread workerThread; 

    protected override void OnDoWork(DoWorkEventArgs e) 
    { 
     workerThread = Thread.CurrentThread; 
     try 
     { 
      base.OnDoWork(e); 
     } 
     catch (ThreadAbortException) 
     { 
      e.Cancel = true; //We must set Cancel property to true! 
      Thread.ResetAbort(); //Prevents ThreadAbortException propagation 
     } 
    } 


    public void Abort() 
    { 
     if (workerThread != null) 
     { 
      workerThread.Abort(); 
      workerThread = null; 
     } 
    } 
} 

在這種情況下,你可以真正中止等待的操作,但也有一些限制(有關詳細信息,關於中止託管線程和一些限制看到Plumbing the Depths of the ThreadAbortException Using Rotor)。

P.S.我同意Oliver的觀點,你應該以更有用的形式包裝InvokeRequired。

+0

很好的答案。我希望這也能在Silverlight中起作用。原來這不是因爲安全限制。調用`Thread.Abort()`將從Silverlight 4(http://msdn.microsoft.com/en-us/library/ty8d3wta(v=VS.95).aspx)開始引發MethodAccessException。哦,這仍然是一個很好的答案。 – 2011-10-05 23:45:43

1

你正在做正確的方式,我相信。你會發現允許你終止或中止一個線程的線程成員,但你不想用它來做這樣的事情。在你的代碼中擁有所有的「取消」檢查可能看起來有點奇怪,但是這允許你準確地控制你何時退出你的線程。如果你「粗暴地」放棄工作者線程,那麼線程無法控制它何時退出,並且可能會損壞狀態。

0

有一件事我不需要調用this.bgwProcessLogin.CancelAsync();因爲你可以設置這個e.Cancel = true;

1

在您的DoWork()函數中,您寫了...。根據顯示的兩個結構的相同結構的多少任務,您可以將此結構重構爲一個自己的方法,將不斷變化的部分作爲參數。

此外,InvokeRequired if-else分支已將輸出字符串加倍。在stackoverflow或網頁上的一個小搜索應該會顯示出一個模式來完成這個加倍。

Evernything其他看起來相當不錯。