Последовательные асинхронные задачи без блокировки - PullRequest
4 голосов
/ 09 ноября 2010

У меня есть приложение C # WPF, использующее довольно изворотливый подход MVVM. В одной из моделей представления ViewModels я хотел бы запускать последовательность задач последовательно, но хотел бы запускать каждую асинхронно с основным потоком. Мне нужна гранулярность, позволяющая сообщать о прогрессе между задачами, но я не хочу блокировать графический интерфейс, когда выполняется какая-либо из задач.

Существует ли стандартный способ достижения этого или "лучшая практика"?

Я реализовал кое-что, что использует BackgroundWorker, и я чувствую себя счастливым и слегка испуганным. Код, с которого все начинается, чувствует себя особенно не на C #. Я чувствую, что должен быть лучший или, по крайней мере, устоявшийся способ сделать это.

Большое спасибо за ваши предложения.

Dan


Вот вариант с булыжником:

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 - это простой набор свойств:

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

Что приводит к 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()
                {

и т.д.

Ответы [ 2 ]

7 голосов
/ 09 ноября 2010

Рассматривали ли вы параллельную библиотеку задач (TPL) в .NET 4.0? Это позволяет вам делать такие вещи:

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

Существует множество вариантов создания, продолжения и остановки задач, построенных на TPL. Это, безусловно, стоит посмотреть.

0 голосов
/ 09 ноября 2010

Я не вижу ничего плохого в вашем подходе.И самое главное: это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...