Rx Workshop: Schedulers

Learn how to model events with duration and how to use the LINQ Join operator to express complex queries involving coincidence.
awsome stuff..
Am I allowed to post the solution of the challange?
Benny
Here is what I came up with
var query = Observable.Join( mouseDown, mouseMove, _ => mouseUp, _ => Observable.Empty<Unit>(), (_, r) => r) .Publish(evt => evt.Zip(evt.Skip(1), (previous, current) => Subtract(current, previous)));
I am having difficulty translating this into query comprehension syntax. Anyone figure that out? Thanks.
Alright here is a working query comprehension version
var query = from start in mouseDown join move in mouseMove on mouseUp equals Observable.Empty<Unit>() into moveGroup let drag = moveGroup.Zip(moveGroup.Skip(1), (prev, curr) => Subtract(curr, prev)) from delta in drag select delta;
Still curious if this could be cleaner. Thanks.
Here is my solution:
var query = Observable.Join(
mouseDown,
mouseMove.Buffer(2),
_ => mouseUp,
m => Observable.Empty<Unit>(),
(_, r) => Subtract(r.Last(),r.First()));
I think my solution is close to the optimum!?
But I had to modify the subscibtion from deltas to absolute points.
var query = mouseDown.Join(mouseMove, l => mouseUp, r => Observable.Empty<Point>(),(l,r)=> Subtract(r,l)); query.Subscribe(pos=> { Canvas.SetLeft(image, pos.X); Canvas.SetTop(image, pos.Y); });
I notied there is a bug when releasing the mouse button from outside of the window. Here is a fix that will merge mouseUp and mouseLeave to accomplish the task. What is normal UI guidance for drag and drop when going outside the window? Thanks.
var mouseLeave = from evt in Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(h => MouseLeave += h, h => MouseLeave -= h) select evt.EventArgs.GetPosition(this); var query = from start in mouseDown join move in mouseMove.Buffer(2) on mouseUp.Merge(mouseLeave) equals Observable.Empty<Unit>() select Subtract(move.Last(), move.First());
Hey what happened to the challenges. They are showing up 404. I was trying to dowload again. Thanks.
Here is my (edited) suggestion:
mouseMove .Buffer(2, 1) .Select(b => b[1] - b[0]) .Window(mouseDown, _ => mouseUp) .Concat();
The Subtract method is not needed.
What I ended up with in query and fluent:
var query = from down in mouseDown join delta in from move in mouseMove.Buffer(2) select Subtract(move.Last(), move.First()) on mouseUp equals Observable.Empty<Unit>() select delta; // var query = Observable.Join( // mouseDown, // mouseMove.Buffer(2).Select(b => Subtract(b.Last(), b.First())), // _ => mouseUp, // _ => Observable.Empty<EventArgs>(), // (_, r) => r);
...though interested if anyone came up with a way to buffer then collapse after the join (I battered my head against that approach for a while before going for this).
Also ended up with the same sln as BennyG first time after missreading the subscribe lambda...
Here is a solution that uses the Scan method:
var query = mouseDown.Join(
mouseMove
.Scan(new { Prev = new Point(), Delta = new Point() },
(current, next) => new { Prev = next, Delta = Subtract(next, current.Prev) })
.Select(x => x.Delta),
down => mouseUp,
delta => Observable.Empty<Unit>(),
(down, delta) => delta);
reopening comments
My solution was based on a similar handling by SelectMany().
private void DragAndDrop() { var mousedown = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(h => image.MouseDown += h, h => image.MouseDown -= h) .Select(e => e.EventArgs.GetPosition(image)); var mousemove = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(h => image.MouseMove += h, h => image.MouseMove -= h) .Select(e => e.EventArgs.GetPosition(canvas)); var mouseup = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(h => image.MouseUp += h, h => image.MouseUp -= h) .Select(e => e.EventArgs.GetPosition(image)); var query = Observable.Join( mousedown ,mousemove ,p1 => mouseup ,p2 => Observable.Empty<Point>() ,(p1, p2) => new { X = p2.X - p1.X, Y = p2.Y - p1.Y } ) .Subscribe(p => { Canvas.SetLeft(image, p.X); Canvas.SetTop(image, p.Y); }); }