web-dev-qa-db-fra.com

Suite de la tâche sur le fil de l'interface utilisateur

Existe-t-il un moyen "standard" d'indiquer qu'une poursuite de tâche doit être exécutée sur le thread à partir duquel la tâche initiale a été créée?

Actuellement, j'ai le code ci-dessous - cela fonctionne, mais garder une trace du répartiteur et créer une deuxième action semble être une surcharge inutile.

dispatcher = Dispatcher.CurrentDispatcher;
Task task = Task.Factory.StartNew(() =>
{
    DoLongRunningWork();
});

Task UITask= task.ContinueWith(() =>
{
    dispatcher.Invoke(new Action(() =>
    {
        this.TextBlock1.Text = "Complete"; 
    }
});
202
Greg Sansom

Appelez la suite avec TaskScheduler.FromCurrentSynchronizationContext():

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

Cela ne convient que si le contexte d'exécution actuel est sur le thread d'interface utilisateur.

326
Greg Sansom

Avec async, vous faites juste:

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);

Pourtant:

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

Si vous avez une valeur de retour que vous devez envoyer à l'interface utilisateur, vous pouvez utiliser la version générique comme ceci:

Ceci est appelé depuis un MVVM ViewModel dans mon cas.

var updateManifest = Task<ShippingManifest>.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());
20
Simon_Weaver

Je voulais juste ajouter cette version parce que c'est un fil tellement utile et je pense que c'est une implémentation très simple. Je l'ai utilisé plusieurs fois dans différents types si application multithread:

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