Dans les technologies XAML (Silverlight, WPF, Windows 8, WP), il est nécessaire d'utiliser le Dispatcher dès lors qu'on veut mettre à jour l'interface utilisateur.
J'ai vu récemment sur le groupe des développeurs Windows Phone une question concernant judicieuse l'utilisation de BeginInvoke :
Si je suis déjà sur le thread de l'UI, est ce que cela sert de faire un BeginInvoke ?
Et par extension, y'a t il des conséquences fâcheuses, comment faire lorsqu'on ne sait pas où on est?
Il faut bien comprendre ce qu'est le Dispatcher: c'est une file d'action à exécuter sur le thread. Ainsi, ajouter une action au Dispatcher, la met à la file.
Ainsi, on peut avoir un comportement plutôt inattendu:
var myBool = false;
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => myBool = true));
if(myBool==true)
Console.WriteLine("content");
else
Console.WriteLine("pas content");
Lors de l'exécution de ce code, si on est sur le Thread de l'UI, contrairement à ce qu'on pourrait penser, on va obtenir "pas content". En effet, le Dispatcher étant une file, lorsque l'on fait un BeginInvoke, l'action est empilée. Elle ne sera dépilée que lorsque le thread de l'UI n'aura plus rien à faire, or il est en train d'exécuter le code autour. L'action sera donc dépilée après le if/then.
Mais comment faire alors ?
Il existe une méthode pour savoir si le code s'exécute sur le thread de l'UI, c'est CheckAccess(). Il est donc possible de s'écrire un petit helper :
public static class DispatcherExtension
{
public static void MyBeginInvoke(this Dispatcher dispatcher, Action action)
{
if(dispatcher.CheckAccess())
{
action();
}
else
{
dispatcher.BeginInvoke(action);
}
}
}
Si on modifie le code qu'on avait au début en remplaçant le BeginInvoke par le MyBeginInvoke, on obtient comme prévu : "content".