Rx Workshop: Reactive Coincidence

Download this episode

Download Video


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

Download the Challenge



Available formats for this video:

Actual format may change based on video formats available and browser capability.

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

    Comments closed

    Comments have been closed since this content was published more than 30 days ago, but if you'd like to send us feedback you can Contact Us.