Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Fathi Bellahcene

.Net m'a tuer!

[framework 4] Les Tasks et le Thread UI

 

Je viens de passer quelques temps au TechDay’s et j’ai pu voir pas mal de session intéressante. Par contre une chose m’a un peu étonné lors de certaines de ces sessions qui abordaient les améliorations du framework .NET (donc le 4.5) : en gros, beaucoup de speaker expliquaient qu’avec l’API Task, il est très compliqué de revenir vers le thread UI sauf à passer par les méthodes old school (BeginInvoke,EndInvoke)…du coup, comme on se tape toute la tuyauterie, plus besoin de Task Sourire.

Pour eux, la solution passe par l’utilisation de async/await ce qui va nous permettre de régler ce problème de manière élégante MAIS mon problème ce que pour moi, il existe des moyen technique assez simple (aussi simple que async/await) pour régler ce problème, en particulier avec PRISM.

Du coup, je me suis dit que ca valait peut être le coup de faire un petit post là dessus.

Je vais donc vous montrer ici comment je fais ca simplement avec la classe Eventaggregator (disponible avec PRISM)

Prenons l’exemple suivant:un bouton qui lorsque l’on click dessus renseigne le contenu d’une textBox avec un petit sleep pour simuler une activitée qui prend du temps:

 

   1: private void button1_Click(object sender, RoutedEventArgs e)
   2:       {
   3:         
   4:           System.Threading.Thread.Sleep(5000);
   5:           textBox1.Text = "toto";
   6:         
   7:       }

si j’exécute mon appli, mon interface est gelée pendant 5 secondes…ce qui est inacceptable pour un utilisateur. Du coup, on souhaite faire ca en parallèle. Mon code devient donc:

   1: private void button1_Click(object sender, RoutedEventArgs e)
   2:    {
   3:        var t = Task.Factory.StartNew(() =>
   4:         {
   5:             System.Threading.Thread.Sleep(5000);
   6:             textBox1.Text = "toto";
   7:         });
   8:  
   9:    }

…mais a l’exécution j’ai la fameuse erreur du Thread UI:

image

et pour régler ca, j’utilise l’EventAggregator:

   1: public partial class MainWindow : Window
   2:   {
   3:       private IEventAggregator eventAggregator = new EventAggregator();
   4:       public MainWindow()
   5:       {
   6:           InitializeComponent();
   7:           eventAggregator.GetEvent<CompositePresentationEvent<string>>().
   8:               Subscribe(val => textBox1.Text = val
   9:                           , ThreadOption.UIThread);
  10:       }
  11:  
  12:       private void button1_Click(object sender, RoutedEventArgs e)
  13:       {
  14:           var t = Task.Factory.StartNew<string>(() =>
  15:           {
  16:               System.Threading.Thread.Sleep(5000);
  17:               return "toto";
  18:           }).ContinueWith((task) => 
  19:               eventAggregator.GetEvent<CompositePresentationEvent<string>>()
  20:               .Publish(task.Result));
  21:       }
  22:  
  23:  
  24:   }
 
Il y a trois choses importantes dans ce code:
  • On passe par un évènement pour synchroniser notre interface graphique avec notre tâche. Cet évènement est complètement géré par PRISM via la classe EventAggregator (qui est une pur merveille). Ici, j’ai utilisé l’objet de base (CompositePresentationEvent<string>) mais dans la pratique on va pouvoir avoir des objets plus complexes et mieux adaptés: si notre traitement renvoi un objet de type Client pour mettre à jours un ensemble de contrôles, on va plutôt utiliser la classe CompositePresentationEvent<Client>.
  • L’utilisation de l’EventAggregator pour repasser dans le thread UI: la méthode Subscirbe qui permet de s’abonner à notre évènement à comme paramètre ThreadOption.UIThread, sans cette option, rien ne marche.
  • A la fin de ma tâche, on lance une action qui à uniquement pour but de lever un évènement avec le résultat du traitement. Comme on est dans le ContinueWith, on est sûr que le traitement est fini et OK.
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: mercredi 8 février 2012 23:33 par fathi
Classé sous : , , ,

Commentaires

richardc a dit :

heu... y'a pas une option dans ContinueWith qui permet de retourner dans le thread UI ?

# février 9, 2012 14:19

fathi a dit :

oui tu as raison et je suis bête de ne pas avoir commencé par ca.

tu peut récupérer avec la classe TaskScheduler un "contexte" que tu peu spécifier dans le ContinueWith.

et dans mon exemple ca irait très bien.

Le seul hic avec cette méthode (la raison pour laquelle je ne l'utilise pas) c'est que tu doit initialiser ton contexte depuis une méthode qui s’exécute dans le thread UI...un peu chiant quand tu te "promène" dans du code un peu complexe.

l'utilisation de l'EventAggregator te permet, entre autre, de ne pas avoir a te poser cette question.

# février 9, 2012 20:25
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01