3

我知道有一个简单的方法可以做到这一点 - 但今晚它打败了我......

我想知道两个事件是否在 300 毫秒内发生,例如双击。

在 300 毫秒内单击鼠标左键两次 - 我知道这是构建反应式框架的目的 - 但该死的,如果我能找到一个很好的文档,其中包含所有扩展运算符的简单示例 - Throttle、BufferWithCount、BufferWithTime - 所有这些都没有'为我做这件事......

4

2 回答 2

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();
        });
}
于 2011-03-08T08:18:12.457 回答
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));
}
于 2011-03-08T04:53:02.400 回答