Continuación de la tarea en el hilo de UI

¿Existe una forma “estándar” para especificar que una continuación de tarea se ejecute en el subproceso desde el que se creó la tarea inicial?

Actualmente tengo el siguiente código: funciona, pero hacer un seguimiento del despachador y crear una segunda Acción parece una sobrecarga innecesaria.

dispatcher = Dispatcher.CurrentDispatcher; Task task = Task.Factory.StartNew(() => { DoLongRunningWork(); }); Task UITask= task.ContinueWith(() => { dispatcher.Invoke(new Action(() => { this.TextBlock1.Text = "Complete"; } }); 

Llame a la continuación con TaskScheduler.FromCurrentSynchronizationContext() :

  Task UITask= task.ContinueWith(() => { this.TextBlock1.Text = "Complete"; }, TaskScheduler.FromCurrentSynchronizationContext()); 

Esto solo es adecuado si el contexto de ejecución actual está en el hilo de UI.

Con la asincronización simplemente lo haces:

 await Task.Run(() => do some stuff); // continue doing stuff on the same context as before. // while it is the default it is nice to be explicit about it with: await Task.Run(() => do some stuff).ConfigureAwait(true); 

Sin embargo:

 await Task.Run(() => do some stuff).ConfigureAwait(false); // continue doing stuff on the same thread as the task finished on. 

Si tiene un valor devuelto que necesita enviar a la interfaz de usuario, puede usar la versión genérica de esta manera:

Esto se llama desde un MVVM ViewModel en mi caso.

 var updateManifest = Task.Run(() => { Thread.Sleep(5000); // prove it's really working! // GenerateManifest calls service and returns 'ShippingManifest' object return GenerateManifest(); }) .ContinueWith(manifest => { // MVVM property this.ShippingManifest = manifest.Result; // or if you are not using MVVM... // txtShippingManifest.Text = manifest.Result.ToString(); System.Diagnostics.Debug.WriteLine("UI manifest updated - " + DateTime.Now); }, TaskScheduler.FromCurrentSynchronizationContext()); 

Solo quería agregar esta versión porque este es un hilo tan útil y creo que esta es una implementación muy simple. Lo he usado varias veces en varios tipos si la aplicación multiproceso:

  Task.Factory.StartNew(() => { DoLongRunningWork(); Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { txt.Text = "Complete"; })); }); 

J escribe tu código como ( Pero usar ContinueWith es una buena práctica, no te preocupes por una sobrecarga innecesaria para el tiempo de ejecución )

  Task task = Task.Factory.StartNew(() => { DoLongRunningWork(); Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { this.TextBlock1.Text = "Complete"; } }); 

Coloque el código de Dispatcher en el bloque finally si desea asegurarse de que esto se ejecute.

Intente evitar TaskScheduler.FromCurrentSynchronizationContext() ya que a partir de este, su Thread actual puede bloquear su Thread UI.