Revisité avec les Reactive Extensions: DataBinding et Mise à Jour depuis Plusieurs Threads

This article is available in english.

Récemment, j'ai écrit un article à propos des WinForms, DataBinding et Mises à Jour depuis plusieurs Threads, où j'expliquais comment externaliser l'exécution d'une méthode accrochée à un événement sur la thread de l'interface utilisateur.

J'ai utilisé alors une technique basée sur un Action<Action> qui prend avantage des "Closures", et le fait que l'action va transporter son contexte jusqu'à l'endroit où il doit être exécuté.

Ce concept d'externalisation peut être revisité avec les Reactive Extensions, et l'interface IScheduler.

L'exemple original

Voyons l'exemple de code original :

1
2
3
4
5
    public MyController(Action<Action> synchronousInvoker)
{
_synchronousInvoker = synchronousInvoker;
...
}

Ce code est le constructeur du contrôleur du formulaire, et l'action "synchronousInvoker" va être définie comme ceci :

1
    _controller = new MyController(a => Invoke(a));

Et utilisée comme ceci :

1
2
3
    _synchronousInvoker(
() => PropertyChanged(this, new PropertyChangedEventArgs("Status"))
);

Ou "Invoke" est en fait Control.Invoke(), utilisé pour exécuter du code sur la Thread de l'interface graphique, la où les mise à jour de contrôles graphiques peuvent être effectuées sans problèmes.

Bien que la technique Action<Action> fonctionne très bien pour parvenir à isoler les rôles, il n'est pas très évident, juste en regardant le constructeur, de savoir ce que l'on doit donner à ce fameux paramètre.

Utiliser l'interface IScheduler

Pour parvenir à isoler l'exécution du contenu des opérateurs du Reactive Framework, l'équipe du Rx a introduit le concept de Scheduler, avec un tas d'implémentations de schedulers communs.

Cela permet d'exposer simplement un moyen de planifier l'exécution d'une méthode dans le contexte qui est n'est pas à la charge de l'utilisateur. Bien souvent, le code qui utilise le scheduler ne veut pas s'occuper du contexte dans lequel est exécute le code. Dans notre cas, on veut exécuter notre code sur la pompe à message des WinForms, et ça tombe bien, "il y a un Scheduler pour ca".

L'exemple précédent peut être facilement mis à jour en utilisant IScheduler à la place de Action<Action>, et d'utiliser la méthode IScheduler.Schedule().

1
2
3
4
5
    public MyController(ISheduler scheduler)
{
_scheduler = scheduler;
...
}

Et de remplacer l'appel par :

1
2
3
    _scheduler.Schedule(
() => PropertyChanged(this, new PropertyChangedEventArgs("Status"))
);

Ce n'est pas une modification très complexe, mais cela le code bien plus compréhensible.

On peut utiliser le Scheduler fourni pour les WinForms, le non-documenté System.Concurrency.ControlScheduler (qui n'est pas présent dans la classe Scheduler parce qu'il ne peut pas être créé statiquement car il requiert une instance de Control) :

1
    _controller = new MyController(new ControlScheduler(this));

Avec "this" qui est une instance de Control.

Au final, le code est plus lisible, et pour ce qui est de faire des tests unitaires sur le Contrôleur, c'est tout à fait faisable avec le System.Concurrency.CurrentThreadScheduler, puisqu'il n'y a pas besoin de changer de threads dans les tests.


Que se passe-t-il avec les Reactive Extensions et Silverlight pour Windows Phone 7 ?

Dans un refactoring très étrange, l'équipe du WP7 a déplacé le IScheduler depuis System.Concurrency vers le très spécifique namespace Microsoft.Phone.Reactive.

Je ne comprend pas vraiment la raison d'un tel changement, et cela a le désagréable effet de rendre incompatible du code qui compilait facilement sur plusieurs plateformes.

Ils ont peut-être considéré que l'implémentation des Reactive Extensions pour Windows Phone était trop différente de la version Desktop... Mais le Compact Framework a été construit sur cette assomption, et la plupart du code est resté dans les même namespaces.

Si quelqu'un a une explication pour ce refactoring étrange, je suis tout ouïe :)

Publié lundi 26 juillet 2010 22:31 par jay
Classé sous , , , ,
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 :

Commentaires


Les 10 derniers blogs postés

- Etendre le Team Web Access de TFS 2012 – Step 0 par Philippe Didiergeorges Aka Philess le il y a 16 heures et 16 minutes

- Simuler facilement l’envoi de mail par Blog de Jérémy Jeanson le 05-22-2013, 12:52

- ProcDump 6.0 : support du filtrage sur messages d'exceptions .NET, des filtres multiples et du ciblage par nom de service par CoqBlog le 05-20-2013, 14:50

- Votez pour le TOP 10 des influenceurs SharePoint francophones ! par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 12:59

- [Conf’SharePoint] Dernier rappel ! :-) par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 09:09

- [ #SharePoint 2013 ] les modèles de sites standards… par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 09:03

- 10 erreurs de compréhension concernant SharePoint… par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 08:27

- Conf’SharePoint : 10 bonnes raisons pour ne pas la rater par Le petit blog de Pierre / Pierre's little blog le 05-14-2013, 02:24

- [Event] Soirée de lancement Agile .NET France à Lyon par Blog Agile/ALM de Vincent THAVONEKHAM le 05-13-2013, 01:29

- .NET / Debug : inspection de la mémoire d'applications .NET (dump ou processus live) : première livraison d'une librairie .NET par Microsoft par CoqBlog le 05-11-2013, 22:21