Rx Workshop: Reactive Coincidence

Play Rx Workshop: Reactive Coincidence
Sign in to queue


Learn how to model events with duration and how to use the LINQ Join operator to express complex queries involving coincidence.

Download the Challenge



Right click to download this episode

The Discussion

  • User profile image

    awsome stuff.. Smiley


  • User profile image

    Am I allowed to post the solution of the challange?


  • User profile image

    Here is what I came up with

                var query = Observable.Join(
                    _ => 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.

  • User profile image

    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.


  • User profile image

    Here is my solution:

    var query = Observable.Join(
    _ => mouseUp,
    m => Observable.Empty<Unit>(),
    (_, r) => Subtract(r.Last(),r.First()));

  • User profile image

    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));
                    Canvas.SetLeft(image, pos.X);
                    Canvas.SetTop(image, pos.Y);

  • User profile image

    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());

  • User profile image

    Hey what happened to the challenges.  They are showing up 404.  I was trying to dowload again.  Thanks.

  • User profile image

    Here is my (edited) suggestion:

    .Buffer(2, 1)
    .Select(b => b[1] - b[0])
    .Window(mouseDown, _ => mouseUp)

    The Subtract method is not needed.

  • User profile image
    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...

  • User profile image

    Here is a solution that uses the Scan method:

    var query = mouseDown.Join(
    .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);

  • User profile image

    reopening comments

  • User profile image

    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
                                            ,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); });

Add Your 2 Cents