Actualizaciones de gráficos de UIThread de TPL BackgroundThread
Frecuentes
Visto 436 veces
1
Todo, tengo un 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!]?
Gracias por su tiempo.
1 Respuestas
1
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
.
Esto se vería algo así como:
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
en lugar de Control.BeginInvoke
, in Windows Forms terminology.
contestado el 22 de mayo de 12 a las 18:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c# winforms user-interface task-parallel-library or haz tu propia pregunta.
I actually do this. In all GUI updates using
uiScheduler
Yo siempre usouiTask.Wait()
(envuelto en untry/catch
para atrapar cualquierAggregateException
s of course), but this "racing" is still happening!? I am confused... - Caballero de la Luna@Killercam Are you doing a "completion" message the same way? - Reed Copsey
The compleation message is handled with a continuation. I don't wait on the continuation, and the continuation delegate is invoked well after this problem arises. - Caballero de la Luna
@Killercam That sounds like something is preventing the UI from updating, since the continuation won't run until the UI thread is free... - Reed Copsey
That's an idea. I will check this tomorrow. Thanks very much for your help and time. - Caballero de la Luna