2012-05-22 24 views
1

所有,我有一个Task在后台线程上运行,并执行一些繁重的工作。我建立的方式是,在完成这一工作时,UI线程会使用进度信息更新GUI,其中一些使用动画.gif文件。看一看以下示例代码来说明这个问题TPL BackgroundThread UIThread图形更新

TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
Task<bool> task = Task.Factory.StartNew(() => 
{ 
    // Heavy work. 
    if (heavyWorkCompleted) 
     MethodToUpdateGui(uiScheduler); // Update DataGridView ImageCell on UI thread 
    // More work. 
} 

我已被的“繁重的工作”执行过程中显示在适当的DGV图像单元中的“进行中”图像时,如果“重工作”是该图像成功更改为(在DGV1中),然后MethodToUpdateGui(uiScheduler)使用DGV1中的此(仅更改)图像更新DGV2。但是,运行MethodToUpdateGui(uiScheduler)时,它有时会更快地更新DataGridView(DGV2)。我的意思是,图像不是我想要的刻度(它应该是由于成功完成),它是“进行中”图像。看起来,DGV并没有足够快地更新我正在做的事情。

有没有更好的方法来做到这一点?我是否敢在GUI更新后旋转后台线程以允许DGV1“赶上”[这太讨厌了!]?

谢谢你的时间。

回答

1

有没有更好的方法来做到这一点?我是否敢在GUI更新后旋转后台线程以允许DGV1“赶上”[这太讨厌了!]?

这里的问题是,TPL使用SynchronizationContext.Post将消息发送到UI线程。当该方法运行时,任务将异步运行,而这将不会立即更新GUI。

如果要确保GUI已更新,最简单的方法是通过等待通过uiScheduler排定的任务来阻止您的MethodToUpdateGui块。

这看起来是这样的:

void MethodToUpdateGui(TaskScheduler uiScheduler) 
{ 
    var updateTask = Task.Factory.StartNew(() => 
    { 
     // update gui 
    }, CancellationToken.None, TaskCreationOptions.None, uiScheduler); 

    // Block until Task completes... 
    updateTask.Wait(); 
} 

这要比旋转,因为它会阻止并获得由TPL自动通知更好。

在Windows Forms术语中,这实际上是在做Control.Invoke而不是Control.BeginInvoke

+0

我其实这样做。在所有使用'uiScheduler'的GUI更新中,我总是使用'uiTask.Wait()'(封装在'try/catch'中来捕获任何'AggregateException'当然),但是这个“赛跑”仍然在发生!我很困惑... – MoonKnight

+0

@Killercam你是否以同样的方式做“完成”信息? –

+0

完成消息的处理有一个延续。我不等待延续,并且在出现这个问题后继续代理被调用。 – MoonKnight