Reputation: 23831
All, I have a Task
that runs on a background thread and does some heavy lifting. The way I have it set up is that whilst this is being done, the UI thread updates the GUI with progress information, some of which use animated .gif files. Take a look at the following example code to illustrate the problem
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task<bool> task = Task.Factory.StartNew(() =>
{
// Heavy work.
if (heavyWorkCompleted)
MethodToUpdateGui(uiScheduler); // Update DataGridView ImageCell on UI thread
// More work.
}
I have a "In Progress" image that is shown in the appropriate DGV image cell during execution of "Heavy Work", if "Heavy Work" is successful this image changes to a tick (in DGV1), then MethodToUpdateGui(uiScheduler)
uses this (just changed) image in DGV1 to update DGV2. However, when the MethodToUpdateGui(uiScheduler)
runs it sometimes updates the DataGridView (DGV2) too fast. What I mean by this, is that the image is not the tick I want (and it should be due to successfull compleation) it is the "In Progress" image. It seems that the DGV is not updating fast enough for what I am doing.
Is there a better way to do this? Do I dare to spin the background thread after the GUI update to allow DGV1 to "catch-up" [this is nasty!]?
Thanks for your time.
Upvotes: 1
Views: 443
Reputation: 564741
Is there a better way to do this? Do I dare to spin the background thread after the GUI update to allow DGV1 to "catch-up" [this is nasty!]?
The issue here is that that TPL uses SynchronizationContext.Post to send the message to the UI thread. When the method runs, the Task will run asynchronously, which will, in turn, not update the GUI immediately.
If you want to make sure that the GUI is updated, the simplest option would be to have your MethodToUpdateGui
block by waiting on the Task scheduled via uiScheduler
.
This would look something like:
void MethodToUpdateGui(TaskScheduler uiScheduler)
{
var updateTask = Task.Factory.StartNew( () =>
{
// update gui
}, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
// Block until Task completes...
updateTask.Wait();
}
This is better than trying to spin, as it will block and get notified by the TPL automatically.
This is effectively doing Control.Invoke
instead of Control.BeginInvoke
, in Windows Forms terminology.
Upvotes: 1