TPL:后台线程完成通知?

时间:2011-09-01 03:30:44

标签: multithreading mvvm task-parallel-library

我有一个MVVM应用程序,它使用.NET 4.0任务并行库在后台处理大量图像。处理在后台线程上完成,后台线程将其进度发布到绑定到进度对话框的视图模型属性。那部分工作正常。但后台线程还需要在完成所有处理后通知主线程,以便可以关闭进度对话框。

这就是我的困境:使用我当前的代码,一旦设置了后台任务,'处理结束'语句就会被命中。但是如果我在两者之间插入task.Wait()语句,它似乎会阻止UI线程,从而阻止进度更新。那么,后台线程如何向主线程发出信号完成?谢谢你的帮助。


以下是创建后台任务的UI线程上的代码:

/* The view should subscribe to the two events referenced below, to 
 * show and close a progress indicator, such as a Progress dialog. */

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

// Process files as a background task
var task = Task.Factory.StartNew(() => DoWork(fileList, progressDialogViewModel));

// Announce that image processing is finished
m_ViewModel.RaiseImageProcessingEndingEvent();

这是后台线程上的DoWork()方法。它使用Parallel.ForEach()语句处理图像文件:

private void DoWork(IEnumerable<string> fileList, ProgressDialogViewModel viewModel)
{
    // Declare local counter
    var completedCount = 0;

    // Process images in parallel
    Parallel.ForEach(fileList, imagePath =>
        {
            ProcessImage(imagePath);
            Interlocked.Increment(ref completedCount); 
            viewModel.Progress = completedCount; 
        });
}

1 个答案:

答案 0 :(得分:2)

您需要在后台任务中添加一个续集,该后台任务将在当前DispatcherSynchronizationContext)线程上触发。这看起来像这样:

task.ContinueWith(t =>
{
   // This will fire on the Dispatcher thread
   m_ViewModel.RaiseImageProcessingEndingEvent();
},
TaskScheduler.FromCurrentSynchronizationContext());

使用指定ContinueWith的{​​{1}}的重载,更具体地说,使用TaskScheduler确保您的连续逻辑将在WPF Dispatcher线程上触发,在该线程中可以安全地访问UI元件。

那就是说,我也应该指出你可能不想修改viewModel.Progress属性,因为如果UI元素绑定到它,它们将从后台线程更新,这不是goo 。相反,你应该在那里分离一个任务,以确保通知在正确的线程上传播。但这样做的诀窍是你的DoWork在启动它时不知道当前的同步上下文,因此你需要在启动原始任务时将其传入。

更新:请参阅我的后续评论,了解我为何更新进度属性的最后一段。