2009-05-05 6 views
4

C# 2008C# отменить DoWork of background worker

Я пользуюсь приведенным ниже кодом для входа в программный телефон. Тем не менее, прогессия для входа - это долгий процесс, поскольку есть много вещей, которые нужно инициализировать, и проверки должны быть сделаны, я только добавил несколько здесь, так как это заставит код долго писать.

В приведенном ниже коде я проверяю, был ли отменен отказ от аннулирования, если CancelAsync был вызван в моем событии click для отмены, перед выполнением каждой проверки. Это верно? Кроме того, если сбой проверки, я также вызываю 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. Я согласен с Оливером, что вы должны обернуть InvokeRequired в более удобной форме.

+0

Хороший ответ. Я надеялся, что это будет работать и в Silverlight. Оказывается, это не из-за ограничений безопасности. Вызов 'Thread.Abort()' будет вызывать исключение MethodAccessException из Silverlight 4 (http://msdn.microsoft.com/en-us/library/ty8d3wta(v=VS.95).aspx). Ну, это хороший ответ. –

+2

@SergeyTeplyakov hi Sergey, у меня есть тот же самый сценарий (один длинный поток, который я хочу прервать, если отмена нажата), но я не вижу, как фактически отменить его из вашего кода/сообщения. Я новичок в фоновых работках, поэтому простите мое невежество ... – ganders

1

Вы делаете это правильно, я считаю. Вы найдете участников потоков, которые позволят вам прервать или прервать поток, но вы не хотите использовать их для чего-то подобного. Может показаться странным иметь все «отмененные» проверки в вашем коде, но это позволяет вам точно контролировать, когда вы выходите из потока. Если вы должны «грубо» прервать рабочий поток, поток не сможет контролировать, когда он выйдет, и может быть поврежден состояние.

0

Есть одна вещь, мне не нужно вызывать this.bgwProcessLogin.CancelAsync(); поскольку вы можете просто установить это e.Cancel = true;

1

В вашей функции DoWork() вы написали .... В зависимости от того, сколько задач одной и той же структуры приближается, как показано на рисунке, вы можете реорганизовать эту структуру в собственный метод, предоставляя переменные части в качестве параметров.

Также эта InvokeRequired ветвь if-else удвоила выходную строку. Небольшой поиск здесь в stackoverflow или в Интернете должен показать вам образец для выполнения этого удвоения.

Evernything еще выглядит неплохо.