Premier pas avec Reactive Extensions (Rx) for .NET

Vous avez déjà surement entendu parler de la programmation réactive ? Et bien nous allons aujourd’hui nous pencher un peu sur la bibliothèque Reactive extension (Rx) qui permet de faire la programmation réactive façon Microsoft.

C’est quoi la programmation réactive?

La programmation réactive permet d’écrire des programmes sous forme d’un ensemble de processus qui s’exécutent de manière synchronisée et communiquent par une diffusion de signaux. Ce paradigme peut être fourni par des langages spécialisées ou par des bibliothèques à l’instar de la bibliothèque réactive extension.

Présentation de Reactive Extensions

Reactive Extensions est un projet de Devlabs qui à connu une certaine notoriété car Erik Meijer, le créateur de Linq fait partir de l’équipe ayant travaillé sur cet API, à la base il a été développé pour SilVerligt et désormais existe aussi pour le .net framework 3.5 et 4 au cœur de cette bibliothèque l’on trouve deux interfaces : IObservable<T> et IObserver<T>. Ces deux interfaces font partie par défaut de .NET 4.0 et de Silverlight 4. La bibliothèque RX fournie donc des API RX permettant de créer des instances de ces interfaces

IObservable est en fait très similaire à IEnumerable, la seule différence est qu’elle est fondé sur une collection (« Pull »), où le consommateur peut choisit quand il veut la prochaine valeur (MoveNext / Current), IObservable représente une collection asynchrone.

public interface IObservable<T>
{
IDisposable Subscribe(IObserver<T> observer);
}



public interface IObserver<in T>
{
void OnCompleted();
void OnError(Exception error);
void OnNext(T value);
}

Notre premier programme avec Rx: Drag and Drop WPF

Commençons notre premier programme WPF Drag and Drop pour vous montrer la puissance de Rx.

Programme

Pour commencer Télécharger et installer Rx for .net.
Créer votre projet WPF ensuite ajouter une référence à System.CoreEx et System.Reactive.
Dans le fichier Window1.axml, remplacer le Grid par

<Canvas>
Image Canvas.Left="23" Canvas.Top="41"
Height="57" Name="image1" Stretch="Fill" Width="70"
Source="Chemin du fichier" />
</Canvas>

Nous voulons que chaque fois que l’utilisateur clique sur l’image et déplace la souris l’image change de position par rapport à celle-ci. Pour cella nous avons besoin d’implémenter trois événements :
- La souris enfoncée sur l’image(mouseDown) ;
- Le déplacement de la souris(mouseUp) ;
- Le relâchement de la souris(mouseMove).

var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(image1, "MouseDown")
select evt.EventArgs.GetPosition(this);
var mouseUp = from evt in Observable.FromEvent<MouseButtonEventArgs>(image1, "MouseUp")
select evt.EventArgs.GetPosition(this);
var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(image1, "MouseMove")
select evt.EventArgs.GetPosition(this);

Maintenant nous pouvons écrire notre requête Linq qui exprime ce que nous voulons faire

var q = from start in mouseDown
from pos in mouseMove.StartWith(start).TakeUntil(mouseUp)
.Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
new { X = cur.X - prev.X, Y = cur.Y - prev.Y }))
select pos;

et enfin on peut souscrire à la séquence observable et mètre les positions à jour

q.ObserveOnDispatcher().Subscribe(value =>
{
Canvas.SetLeft(image1, Canvas.GetLeft(image1) + value.X);
Canvas.SetTop(image1, Canvas.GetTop(image1) + value.Y);
});


Le code complet à mettre dans le constructeur de la classe Window1 au niveau du code metier(fichier Window1.axml.cs).

public Window1()
{
InitializeComponent();

// creation des l'evenements pour la souris
var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(image1, "MouseDown")
select evt.EventArgs.GetPosition(this);
var mouseUp = from evt in Observable.FromEvent<MouseButtonEventArgs>(image1, "MouseUp")
select evt.EventArgs.GetPosition(this);
var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(image1, "MouseMove")
select evt.EventArgs.GetPosition(this);

//On defini notre requete Linq qui nous permtra de faire le Drag and Drop
var q = from start in mouseDown
from pos in mouseMove.StartWith(start).TakeUntil(mouseUp)
.Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
new { X = cur.X - prev.X, Y = cur.Y - prev.Y }))
select pos;


// et la on soucrire à la sequence observable et metre les positions à jour

q.ObserveOnDispatcher().Subscribe(value =>
{
Canvas.SetLeft(image1, Canvas.GetLeft(image1) + value.X);
Canvas.SetTop(image1, Canvas.GetTop(image1) + value.Y);
});


}


Nous venons de finir avec un exemple qui vous montre la puissance de RX, vous pouvez le faire pour une application Winform ou silverlight.
Nous avons juste effleurer l’une des immense possibilité que nous offre cette bibliothèque.

Références

Telecharger RX
Brief Introduction to the Reactive Extensions for .NET, Rx
Rx on channel9

Laisser un commentaire