我知道,有一个简单的方法来做到这一点 - 但它已经打败我今晚......无框架/的DoubleClick
我想知道,如果发生在彼此的300毫秒的两个事件,如在双击。
在300毫秒内点击两次鼠标左键 - 我知道这就是响应式框架的构建 - 但该死的如果我能找到一个好的文档,其中包含所有扩展操作的简单示例 - Throttle,BufferWithCount,BufferWithTime - all其中just werent'正在为我做...
我知道,有一个简单的方法来做到这一点 - 但它已经打败我今晚......无框架/的DoubleClick
我想知道,如果发生在彼此的300毫秒的两个事件,如在双击。
在300毫秒内点击两次鼠标左键 - 我知道这就是响应式框架的构建 - 但该死的如果我能找到一个好的文档,其中包含所有扩展操作的简单示例 - Throttle,BufferWithCount,BufferWithTime - all其中just werent'正在为我做...
的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();
});
}
编辑 - 使用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));
}
谢谢以及 - 我接近你打电话的答案,但认为FastSubject有趣的是,确保所有来到在同一线程上的事件。虽然+1了! 我很好奇你在哪里了解到Reactive Framework,以及所有各种扩展的文档来源。 – codeputer 2011-03-08 16:01:06
@codputer - 我想你误会了。我的示例使用'FastSubject',因为不需要线程处理(即鼠标点击总是来自UI线程)。这是正常的Subject实现,可防止来自多个线程的值进入。 – 2011-03-08 20:35:47
非常感谢,我从我认为是一件非常简单的事情中学到了很多东西。哪里有所有这些各种扩展的完整文档?你是如何学习它们的? 我唯一的问题是关于重复,因为我很困惑,当观察者超出范围(害羞而不是UnSubscribe)?如果我在我的课程的构造函数中订阅,范围是如何建立的?我知道OnComplete会调用dispose,但是在什么时候正在监听事件实际完成? – codeputer 2011-03-08 15:59:10
你什么时候使用Zip? – codeputer 2011-03-08 15:59:28
@codputer - 我的大部分知识来自于我在将框架移植到actionscript时针对每个操作员编写单元测试的事实。我记录了大部分操作员,虽然他们已经过时了(我知道Throttle文档是错误的) - https://github.com/richardszalay/rxas/wiki/Operators – 2011-03-08 20:37:58