2010-11-09 8 views
4

J'ai une application C# WPF utilisant une approche MVVM plutôt noddy. Dans l'un des ViewModels, je voudrais exécuter une séquence de tâches de manière séquentielle, mais souhaiterais que chaque tâche soit asynchrone au thread principal. Je veux la granularité d'être en mesure de signaler les progrès entre les tâches, mais je ne veux pas bloquer l'interface graphique tant que l'une des tâches est en cours d'exécution.Tâches asynchrones séquentielles sans blocage

Existe-t-il un moyen standard d'y parvenir, ou une «meilleure pratique»?

J'ai mis en place quelque chose qui utilise BackgroundWorker que je sens à la fois heureux et légèrement horrifié avec. Le code pour donner un coup de pied au tout se sent surtout non-C# ish. Je pense qu'il doit y avoir une meilleure ou, au moins, une façon établie de le faire.

Un grand merci pour vos suggestions.

Dan


Voici l'option bricolé:

protected void runAsyncTask(SequentialTask seqTask) 
    { 
     if (HasErrored) return; 

     DoWorkEventHandler worker = (s, e) => 
     { 
      setTaskStartStatusMessage(seqTask.TaskMessage); 
      ShowProgress = true; 
      seqTask.Task((BackgroundWorker)s); 
     }; 

     ProgressChangedEventHandler progress = (s, e) => 
     { 
      if (seqTask.TaskProgress != null) 
       seqTask.TaskProgress(e.ProgressPercentage, e.UserState); 
     }; 

     RunWorkerCompletedEventHandler done = null; 
     done = (s, e) => 
     { 
      ShowProgress = false; 
      if (e.Error != null) 
      { 
       HasErrored = true; 
       displayTaskExceptionMessage(e.Error, seqTask.TaskMessage); 
      } 
      else 
      { 
       setTaskCompleteStatusMessage(seqTask.TaskMessage); 
       if (seqTask.TaskComplete != null) 
        seqTask.TaskComplete(); 
      } 
      ((BackgroundWorker)s).RunWorkerCompleted -= done; 
      ((BackgroundWorker)s).DoWork -= worker; 
      ((BackgroundWorker)s).ProgressChanged -= progress; 

      if (seqTask.NextTask != null && (seqTask.CanExecuteNext == null ? true : seqTask.CanExecuteNext())) 
       runAsyncTask(seqTask.NextTask); 
     }; 

     if (seqTask.TaskProgress != null) 
      backgroundWorker.WorkerReportsProgress = true; 
     backgroundWorker.DoWork += worker; 
     backgroundWorker.RunWorkerCompleted += done; 
     backgroundWorker.ProgressChanged += progress; 
     backgroundWorker.RunWorkerAsync(); 
    } 

SequentialTask est juste un simple ensemble de propriétés:

public class SequentialTask 
{ 
    public Action<BackgroundWorker> Task { get; set; } 
    public String TaskMessage { get; set; } 
    public Func<bool> CanExecuteNext { get; set; } 
    public Action<int, object> TaskProgress { get; set; } 
    public Action TaskComplete { get; set; } 
    public SequentialTask NextTask { get; set; } 
} 

Ce qui conduit à la syntaxe Perl comme de:

runAsyncTask(new SequentialTask() 
     { 
      Task = (x) => loadFile(), 
      TaskMessage = "Load File", 
      CanExecuteNext = null, 
      NextTask = new SequentialTask() 
      { 
       Task = (x) => validateImport(), 
       TaskMessage = "Validate Input Lines", 
       TaskComplete =() => 
       { 
        if (!ImportIsValid) 
         displayValidationMessages(); 
       }, 
       CanExecuteNext =() => ImportIsValid, 
       NextTask = new SequentialTask() 
       { 

etc.

+0

Coroutines ou Reactive Framework sont un bon ajustement pour cela: http://csharperimage.jeremylikness.com/2010/03/sequential-asynchronous-workflows-in.html – Jay

+0

Salut Jay, merci pour le lien - a jeté un coup d'oeil Et c'est quelque chose que je vais certainement passer le temps à faire tourner ma tête mais je pense que la suggestion d'Adam sur le TPL est là où je vais passer mes efforts initiaux. –

Répondre

7

Avez-vous regardé la bibliothèque parallèle de tâches (TPL) dans .NET 4.0? Cela vous permet de faire des choses comme ceci:

Task firstTask = new Task(()=>RunStepOne()); 
firstTask.ContinueWith(task=>()=>RunSecondStep()); 
firstTask.Start(); 

Il y a une tonne d'options pour la création, la poursuite et l'arrêt des tâches construites sur le TPL. Cela vaudra certainement le coup d'oeil.

+0

Sans compter que cela vous donnera une longueur d'avance lorsque C# 5 est libéré. –

+0

Merci Adam, c'est le prochain chapitre de C# en bref - Je vais y aller et jeter un coup d'œil. De l'extrait que vous avez montré, il semble certainement beaucoup plus propre que l'enchaînement des structures récursives. –

+0

Je pense que cela me donne définitivement ce que je veux et dans un "out-of-the-box", merci encore. –

0

Je ne vois rien de mal dans votre approche. Et la chose la plus importante est: cela fonctionne.