System.Reactive puzzle

After working on the Reactive Framework with Erik, Wes and the rest of our team for over a year, it is great to see  that the word about System.Reactive is out (as described here, here, here and here).

I thought it might be fun to post a little puzzle challenge showing the power of the Reactive Framework. I asked the same question to my team members a while back and everyone got a different solution, from very declarative to very imperative.

here is the puzzle:

A while back, if found a jQuery implementation of tripple click of course this can be done very elegantly in Rx.

The first question is: can you implement this using Rx (for the Silverlight Button)? 
the second question is: can you generalize it like this:

public

static IObservable<RoutedEventArgs> GetMultiClickScan(this ButtonBase button, int count, int multiClickSpeedInMilliSeconds)

The third and final question is: Can you implement this without timers?

To give you a head start, here is the code to get an IObservable<RoutedEventArgs>that fires for each click:

var

click = Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>
    (i => i.Invoke, i => button.Click += i , i => button.Click -= i).Select(e => e.EventArgs);

Rules:
-feel free to ask questions in the comments if you're stuck, can't promise I'll be able to answer you immediately or give everything away though :)
-feel free to post answers in the comments, if you don't want to be spoiled, don't read the comments :)
-No prizes, only eternal satisfaction with an awesome implementation can be won here :)

I'll post some of our teams answers to this puzzle in a couple of days..

Comments

  • Anonymous
    August 12, 2009
    amazing Rx, hier are my first solutions
  1. solution with Scan return click    .Scan(new { e = new RoutedEventArgs(), t = DateTime.Now, c = 0 }, (a, e) => new    {        e,        t = DateTime.Now,        c = ((DateTime.Now - a.t).TotalMilliseconds < multiClickSpeedInMilliSeconds) ? (a.c + 1) : 1 })    .Skip(1)    .Where(a => a.c % count == 0)    .Select(a => a.e);
  2. solution without Scan return click    .Skip(count)    .Zip(click.Select(_ => DateTime.Now), (e, t) => new { e, t = DateTime.Now - t })    .Where(e => e.t.TotalMilliseconds < multiClickSpeedInMilliSeconds)    .Select(e => e.e)
  • Anonymous
    August 12, 2009
    Jeffrey:  Spoke too soon.  :-) Your solutions work - and very well too. Very nice!  Wish I'd thought of them :-).

  • Anonymous
    November 18, 2009
    My solution: http://snipt.org/pYj