2010-07-15 5 views
5

J'ai une interface utilisateur qui affiche l'état des opérations de longue durée (téléchargement de certains fichiers texte de ftp). Pour mes fins, j'utilise backgroundworker et je ne peux pas annuler l'opération.Annuler backgroundworker

void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 

     try 
     { 
      int rowIndex = (int)e.Argument; 

      //begin UI update 
      StartWaitingBar(rowIndex); 
      //get provider id cell 
      GridViewDataRowInfo row = _proivderGridView.Rows[rowIndex]; 
      GridViewCellInfo provIdCell = row.Cells[ "ProviderId" ]; 

      var providerData = GetProviderData(Convert.ToInt32(provIdCell.Value)); 
      var provider = ProviderFactory.CreateProvider(providerData); 
      provider.Synchronize(); 
      e.Result = rowIndex; 

     } 
     catch (Exception exception) 
     { 
      return; 
     } 
    } 

et le code pour la création des travailleurs:

  BackgroundWorker worker = new BackgroundWorker(); 
      worker.DoWork += worker_DoWork; 
      worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
      worker.WorkerSupportsCancellation = true; 
      worker.RunWorkerAsync(args.RowIndex); 
      _syncWorkers.Add(providerId,worker); 
      ... 
      var worker = _syncWorkers[providerId]; 

      if(worker.IsBusy) 
      { 
       worker.CancelAsync(); 
      } 
      else 
      { 
       worker.RunWorkerAsync(args.RowIndex); 
      } 

solution fournie here ne semble pas fonctionner pour moi beacuse cela fonctionne pour les opérations récurrentes (pour lequel travailleur de fond est créée, je suppose). Dois-je utiliser des threads (annuler et joindre) à mes fins parce que je devrais fournir des possibilités pour l'utilisateur d'annuler une opération de longue durée?

Besoin de votre conseil.

Merci d'avance.

Répondre

7

Vous ne pouvez pas utiliser Backgroundworker.CancelAsync() pour annuler une longue course d'action E/S. Comme rifnl a répondu, le DoWork doit vérifier worker.CancellationPending et mettre e.Cancel. Mais vous ne devriez pas utiliser Thread.Abort() non plus. Cela pourrait déstabiliser votre processus.

La solution dont vous avez besoin doit provenir de provider.Synchronize(); en quelque sorte. PS: est horrible. Supprimez l'ensemble try/catch et laissez le Bgw gérer les exceptions.

+0

Alternativement, s'il est possible de donner la valeur Synchronize a TimeOut, vous pouvez mettre la synchronisation dans un while (! E.CancellationPending) privider.Synchronize (TimeOut); // si possible boucle, tout en continuant la fonction que vous avez actuellement. – greggorob64

2

Vous devez vérifier e.Cancel dans votre méthode DoWork, qui manque dans votre extrait de code, mais vous devez aussi changer votre méthode de téléchargement pour un appel asynchrone, vous appelez la méthode et attendez la réponse dans le dowork. Ce qui est possible, mais il ne vérifiera pas le drapeau d'annulation en temps moyen.

Vérifiez la solution que vous avez affichée (ligne 3):

void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    while(!e.Cancel) 
    { 
     // do something 
    } 

    _resetEvent.Set(); // signal that worker is done 
} 
+0

Merci pour votre réponse! Je comprends votre point de vue, mais dois-je utiliser du backgraound worker? Je peux utiliser l'opération async (comme je l'ai fait initialement) et utiliser AutoResetEvent pour réaliser l'annulation ... – Sharov

+0

Comme riffnl l'a dit, 'BackgroundWorker' supporte l'annulation. Vous n'avez pas besoin d'utiliser 'BackgroundWorker', mais je recommande de déplacer * up * en abstraction vers' Task', plutôt que vers * down * en abstraction pour les délégués asynchrones. –

+0

@rifnl, ce n'est pas e.Cancel. –