继续几项任务

时间:2011-09-05 23:04:33

标签: mvvm task-parallel-library

我正在使用TPL在MVVM应用程序的后台线程上连续执行两项任务。任务正在运行时,应用程序将显示“进度”对话框。因此,我的MVVM命令的Execute()方法首先在主视图模型中引发ImageProcessingStarting事件。视图通过显示“进度”对话框来响应事件。然后,该命令启动第一个任务,继续第二个任务,并通过在主视图模型中引发ImageProcessingEnding事件来执行最后的“继续”。视图通过关闭“进度”对话框来响应事件。代码如下。

两个后台任务都正常执行,但“进度”对话框在第一个任务完成后提前关闭,而不是在第二个任务之后关闭。我希望有人可以告诉我为什么,以及如何解决问题。谢谢你的帮助。


public void Execute(object parameter)
{
    ...

    // Announce that image processing is starting
    m_ViewModel.RaiseImageProcessingStartingEvent();

    // Set up a cancellation token source
    var tokenSource = new CancellationTokenSource();
    m_ViewModel.ProgressDialogViewModel.TokenSource = tokenSource;

    // Background Task #1: Add time stamps to files
    var task = Task.Factory.StartNew(() => this.AddTimeStampsToFiles(fileList, progressDialogViewModel));

    /* The Progress dialog is closing at this point! */

    // Background Task #2: Resequence files
    task.ContinueWith(t => this.ResequenceFiles(fileList, progressDialogViewModel));

    /* The Progress dialog should close at this point. */

    // Announce that image processing is finished
    task.ContinueWith(t => m_ViewModel.RaiseImageProcessingEndingEvent(), TaskScheduler.FromCurrentSynchronizationContext());
}

2 个答案:

答案 0 :(得分:1)

根据MSDN

  

Task.ContinueWith方法

     

创建在目标时异步执行的延续   任务完成。

这意味着当主任务完成时,两个ContinueWith调用中的其他项将彼此并行运行。

为了证明这一点,请使用以下代码:

System.Threading.Tasks.Task task = new System.Threading.Tasks.Task(() => Console.WriteLine("1"));
task.ContinueWith((t) => { System.Threading.Thread.Sleep(1000); Console.WriteLine("2"); });
task.ContinueWith((t) => Console.WriteLine("3"));

输出窗口将显示为:

1
3
2

为了帮助解决您的问题,我一直使用System.ComponentModel.BackgroundWorker来连续运行任务。可能有更好的方法,但现在这对我有用。

public void Execute(object parameter)
{
    BackgroundWorker bgW = new BackgroundWorker();

    bgW.DoWork += (s, args) =>
    {
        AddTimeStampsToFiles(fileList, progressDialogViewModel);
        ResequenceFiles(fileList, progressDialogViewModel);
    };

    bgW.RunWorkerCompleted += (s, args) =>
    {
        m_ViewModel.RaiseImageProcessingEndingEvent();
    }; 

    m_ViewModel.RaiseImageProcessingStartingEvent();
    bgW.RunWorkerAsync();
}

为此,您可能需要将fileListprogressDialogViewModel值传递给bgW.RunWorkerAsync()方法。

对于多个值,我通常使用Dictionary<string, object>对象,因此我可以按名称引用值。

希望这有帮助。

答案 1 :(得分:0)

找到我的答案。在我的原始代码中,第二个和第三个任务都是第一个任务的延续。我更改了代码,为原始任务(taskOne)和延续任务(taskTwotaskThree)创建了单独的任务。然后,taskTwo继续taskOnetaskThree继续taskTwo,如下所示:

// Background Task #1: Add time stamps to files
var taskOne = Task.Factory.StartNew(() => AddTimeStampsToFiles(fileList, progressDialogViewModel));

// Background Task #2: Resequence files
var taskTwo = taskOne.ContinueWith(t => this.ResequenceFiles(fileList, progressDialogViewModel));

// Announce that image processing is finished
var taskThree = taskTwo.ContinueWith(t => m_ViewModel.RaiseImageProcessingEndingEvent(), TaskScheduler.FromCurrentSynchronizationContext());

我接受了Fatty的回答,因为它确实提供了一个可行的选择。但是,我在我的应用程序中使用此答案中的方法,因为我正在使用TPL。