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

- [PowerShell 3] Télécharger et installer la documentation en ligne par Blog de SPBrouillet (Pierrick BROUILLET) le il y a 19 heures et 43 minutes

- [#SharePoint 2010][#SQLServer 2012] AlwaysOn pour SharePoint (1/4) : Configuration (1ère partie)… par Le blog de Patrick [MVP SharePoint] le 05-16-2012, 12:10

- Job Day @MIC Brussels - .Net Developers on Mobile applications par Le Blog (Vert) d'Arnaud JUND le 05-15-2012, 20:26

- [SharePoint 2010] – SharePoint 2010, Windows (Server) 8 et des erreurs IIS sont dans une VM… par Blog de SPBrouillet (Pierrick BROUILLET) le 05-14-2012, 12:10

- [Event] Windows Azure dev Camp le 20 juin! par Fathi Bellahcene le 05-13-2012, 09:29

- Comment redimensionner une image avec WinRT : plusieurs solutions par Richard Clark le 05-11-2012, 15:43

- Event : Swiss SharePoint Club Meeting #20 à Yverdon par Blog Technique de Romelard Fabrice le 05-11-2012, 15:24

- Réflechissons un peu ce matin à propos des ORM par Richard Clark le 05-11-2012, 08:48

- #SharePoint Solutions Roadshow le 5 juin à Issy ! par Le blog de Patrick [MVP SharePoint] le 05-09-2012, 15:10

- SharePoint : Mes alertes ne marchent pas … Que faire ? Comment réparer ou agir ? par The Mit's Blog le 05-08-2012, 14:59