Reactive Programming, Posting # 4
Continuing the discussion of Reactive Programming, this posting, based on a video from the Rx team, will create and annotate Drag and Drop using the Rx toolkit. In part 1 we’ll track mouse movements, in part 2 we’ll implement drag and drop on an image.
Applying reactive programming to mouse movements treats the mouse as an observable collection of points and allows you to subscribe to that collection so that as new points become available you are notified.
To get started, create a new WPF Application (because we want to play with mouse movements).
Replace the grid with a canvas, and on the canvas add a TextBlock and an Image. .
<Canvas> <TextBlock Name="textBlock" Text="Rx Drag and Drop" /> <Image Name="image" Source="d:\avatar.png" Width="100" Height="100" Canvas.Left="25" Canvas.Top="25" /> </Canvas>
Make sure you’ve installed the Rx for .NET 4 libraries (available here) and in this project add references to System.CoreEx and System.Reactive.
We want to observe the mouse down/up and move events. The syntax is to create a variable, and assign to that variable the observer that we’ll create from the event. The FromEvent construct takes the name of the event args, the object on which the event will be raised, and the name of the event. We can then select what values we want.
var mousedown = from evt in Observable.FromEvent <MouseButtonEventArgs>( this, "MouseDown" ) select evt.EventArgs.GetPosition( this );
We do the same with mouseup and mouse move
var mouseup = from evt in Observable.FromEvent <MouseButtonEventArgs>( this, "MouseUp" ) select evt.EventArgs.GetPosition( this ); var mousemove = from evt in Observable.FromEvent <MouseEventArgs>( this, "MouseMove" ) select evt.EventArgs.GetPosition( this );
We can now create an observable that listens to the mouse positions from the time the mouse goes down and ending when the mouse goes up,
var q = from start in mousedown from pos in mousemove.StartWith( start ) .TakeUntil( mouseup ) select pos;
We can then subscribe to this observable and display the positions while the mouse button is down,
q.ObserveOnDispatcher() .Subscribe( value => textBlock.Text = value.ToString() );
The ObserveOnDispatcher forces back to the visual thread (so as not to throw an exception).
The subscribe method takes an Action, and so we can pass in a delegate to a method that assigns the string representation of the value to our text box. In this case, as is customary we use a lambda expression to make the code easier to read and maintain.