Reactive Programming, Posting # 7
In Part 1 of this 2 part posting we looked at capturing the mouse movements. The key code in Part 1 was,
var q = from start in mousedown from pos in mousemove.StartWith( start ) .TakeUntil( mouseup ) select pos;
Now, in part 2, rather than just getting the coordinates of the mouse, we want to find the delta so that we can move the image with the changes in the mouse position.
Part 1 was written for WPF, but as was pointed out by Jim Wooley in a comment on part 1, the same code can be written for Silverlight or Windows Phone by modifying the MouseDown to MouseLeftButtonDown and MouseUp to MouseLeftButtonUp. |
For Windows Phone, make sure that you add a reference to Microsoft Phone Reactive and to System Observable and for ths program, you’ll need to ensure that you have using statements for Microsoft.Phone.Reactive, System.Windows.Input, System.Windows.Controls and System.Linq.
We’ll begin by redefining mouseDown and MouseUp
var mousedown = from evt in Observable.FromEvent <MouseButtonEventArgs>( image, "MouseLeftButtonDown" ) select evt.EventArgs.GetPosition( image ); var mouseup = from evt in Observable.FromEvent <MouseButtonEventArgs>( this, "MouseLeftButtonUp" ) select evt.EventArgs.GetPosition( this ); var mousemove = from evt in Observable.FromEvent <MouseEventArgs>( this, "MouseMove" ) select evt.EventArgs.GetPosition( this );
Notice that mousedown and mouseup use the MouseLeftButtonDown and MouseLeftButtonUp events, respectively and that mousedown sets the image as the source of the event
We are using a select statement on mouseup, but the truth is we don’t care about the mouse position, just the fact that the event was fired, so we can simplify this middle definition to
var mouseup = Observable.FromEvent <MouseButtonEventArgs>( this, "MouseLeftButtonUp" );
Our query statement becomes one of finding the start position and end position (for each movement of the mouse while the button is down) and then subtracting the end from the start to get the change in position for the image.
var q = from start in mousedown from end in mousemove.TakeUntil( mouseup ) select new { X = end.X - start.X, Y = end.Y - start.Y };
We can then use that query to subscribe to the mouse as if it were an observable collection of points.
q.Subscribe( value => { Canvas.SetLeft( image, value.X ); Canvas.SetTop( image, value.Y ); } );
Note that image is the name of the Image object defined in Xaml.
The net effect is that if you click on the image, you can drag it around the phone’s canvas until you release the mouse button.