Serial asynchronous tasks without blocking

I have a C # WPF application using a fairly innovative MVVM approach. In one of ViewModels, I would like to execute a sequence of tasks sequentially, but I would like to start each asynchronous main thread. I want the granularity to be able to report progress between tasks, but I do not want to block the graphical interface when any of the tasks is performed.

Is there a standard way to achieve this goal or โ€œbest practiceโ€?

I implemented something that uses BackgroundWorker that I immediately feel happy and a little horrified. The code, to discard all this, feels especially non-C # ish. I believe that there should be a better, or at least an established way to do this.

Thanks so much for your suggestions.

Dan


Here's the cobbled-together option:

 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 is just a simple set of properties:

 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; } } 

This results in syntax similar to Perl:

 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() { 

and etc.

+4
source share
2 answers

Have you looked at the parallel task library (TPL) in .NET 4.0? This allows you to do things like this:

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

There are many possibilities for creating, continuing and stopping tasks built on TPL. It is definitely worth a look.

+7
source

I see nothing wrong with your approach. And most importantly: it works.

0
source

All Articles