我知道有一个简单的方法可以做到这一点 - 但今晚它打败了我......
我想知道两个事件是否在 300 毫秒内发生,例如双击。
在 300 毫秒内单击鼠标左键两次 - 我知道这是构建反应式框架的目的 - 但该死的,如果我能找到一个很好的文档,其中包含所有扩展运算符的简单示例 - Throttle、BufferWithCount、BufferWithTime - 所有这些都没有'为我做这件事......
我知道有一个简单的方法可以做到这一点 - 但今晚它打败了我......
我想知道两个事件是否在 300 毫秒内发生,例如双击。
在 300 毫秒内单击鼠标左键两次 - 我知道这是构建反应式框架的目的 - 但该死的,如果我能找到一个很好的文档,其中包含所有扩展运算符的简单示例 - Throttle、BufferWithCount、BufferWithTime - 所有这些都没有'为我做这件事......
该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));
}