2011-03-08 68 views
2

我知道,有一个简单的方法来做到这一点 - 但它已经打败我今晚......无框架/的DoubleClick

我想知道,如果发生在彼此的300毫秒的两个事件,如在双击。

在300毫秒内点击两次鼠标左键 - 我知道这就是响应式框架的构建 - 但该死的如果我能找到一个好的文档,其中包含所有扩展操作的简单示例 - Throttle,BufferWithCount,BufferWithTime - all其中just werent'正在为我做...

回答

9

TimeInterval方法会给你值之间的时间。

public static IObservable<Unit> DoubleClicks<TSource>(
    this IObservable<TSource> source, TimeSpan doubleClickSpeed, IScheduler scheduler) 
{ 
    return source 
     .TimeInterval(scheduler) 
     .Skip(1) 
     .Where(interval => interval.Interval <= doubleClickSpeed) 
     .RemoveTimeInterval(); 
} 

如果你想确保三重点击不触发值,你可以只在一个炎热观察到的使用Repeat(我已经使用了FastSubject这里的点击次数都将迎来一个线程,因此不需要正常人的沉重感):

public static IObservable<TSource> DoubleClicks<TSource>(
    this IObservable<TSource> source, TimeSpan doubleClickSpeed, IScheduler scheduler) 
{ 
    return source.Multicast<TSource, TSource, TSource>(
     () => new FastSubject<TSource>(), // events won't be multithreaded 
     values => 
     { 
      return values 
       .TimeInterval(scheduler) 
       .Skip(1) 
       .Where(interval => interval.Interval <= doubleClickSpeed) 
       .RemoveTimeInterval() 
       .Take(1) 
       .Repeat(); 
     }); 
} 
+0

非常感谢,我从我认为是一件非常简单的事情中学到了很多东西。哪里有所有这些各种扩展的完整文档?你是如何学习它们的? 我唯一的问题是关于重复,因为我很困惑,当观察者超出范围(害羞而不是UnSubscribe)?如果我在我的课程的构造函数中订阅,范围是如何建立的?我知道OnComplete会调用dispose,但是在什么时候正在监听事件实际完成? – codeputer 2011-03-08 15:59:10

+0

你什么时候使用Zip? – codeputer 2011-03-08 15:59:28

+0

@codputer - 我的大部分知识来自于我在将框架移植到actionscript时针对每个操作员编写单元测试的事实。我记录了大部分操作员,虽然他们已经过时了(我知道Throttle文档是错误的) - https://github.com/richardszalay/rxas/wiki/Operators – 2011-03-08 20:37:58

3

编辑 - 使用TimeInterval()来代替。

Zip() and Timestamp()运营商可能是一个好的开始。

var ioClicks = Observable.FromEvent<MouseButtonEventHandler, RoutedEventArgs>(
             h => new MouseButtonEventHandler(h), 
             h => btn.MouseLeftButtonDown += h, 
             h => btn.MouseLeftButtonDown -= h); 
var ioTSClicks = ioClicks.Timestamp(); 

var iodblClicks = ioTSClicks.Zip(ioTSClicks.Skip(1), 
           (r, l) => l.Timestamp - r.Timestamp) 
          .Where(tspan => tspan.TotalMilliseconds < 300); 

可能最好通过测试调度器进行测试,所以你知道你会得到什么:

[Fact] 
public void DblClick() 
{ 
    // setup 
    var ioClicks = _scheduler.CreateHotObservable(
        OnNext(210, "click"), 
        OnNext(220, "click"), 
        OnNext(300, "click"), 
        OnNext(365, "click")) 
        .Timestamp(_scheduler); 

    // act 
    Func<IObservable<TimeSpan>> target = 
     () => ioClicks.Zip(ioClicks.Skip(1), 
          (r, l) => l.Timestamp - r.Timestamp) 
         .Where(tspan => tspan.Ticks < 30); 
    var actuals = _scheduler.Run(target); 

    // assert 
    Assert.Equal(actuals.Count(), 1); 
    // + more 
} 
public static Recorded<Notification<T>> OnNext<T>(long ticks, T value) 
{ 
    return new Recorded<Notification<T>>(
     ticks, 
     new Notification<T>.OnNext(value)); 
} 
+0

谢谢以及 - 我接近你打电话的答案,但认为FastSubject有趣的是,确保所有来到在同一线程上的事件。虽然+1了! 我很好奇你在哪里了解到Reactive Framework,以及所有各种扩展的文档来源。 – codeputer 2011-03-08 16:01:06

+0

@codputer - 我想你误会了。我的示例使用'FastSubject',因为不需要线程处理(即鼠标点击总是来自UI线程)。这是正常的Subject实现,可防止来自多个线程的值进入。 – 2011-03-08 20:35:47