我正在使用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());
}
答案 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();
}
为此,您可能需要将fileList
和progressDialogViewModel
值传递给bgW.RunWorkerAsync()
方法。
对于多个值,我通常使用Dictionary<string, object>
对象,因此我可以按名称引用值。
希望这有帮助。
答案 1 :(得分:0)
找到我的答案。在我的原始代码中,第二个和第三个任务都是第一个任务的延续。我更改了代码,为原始任务(taskOne
)和延续任务(taskTwo
和taskThree
)创建了单独的任务。然后,taskTwo
继续taskOne
,taskThree
继续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。