反应式框架/DoubleClick

发布于 2024-10-20 13:13:48 字数 228 浏览 4 评论 0原文

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

我想知道两个事件是否在 300 毫秒内发生,就像双击一样。

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

I know that there is an easy way to do this - but it has beaten me tonight ...

I want to know if two events occur within 300 milliseconds of each other, as in a double click.

Two leftdown mouse clicks in 300 milliseconds - I know this is what the reactive framework was built for - but damn if I can find a good doc that has simple examples for all the extenstion operatores - Throttle, BufferWithCount, BufferWithTime - all of which just werent' doing it for me....

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

何以笙箫默 2024-10-27 13:13:48

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();
        });
}

The TimeInterval method will give you the time between values.

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();
}

If you want to be sure that triple clicks don't trigger values, you could just use Repeat on a hot observable (I've used a FastSubject here as the clicks will all come on one thread and therefore don't require the heaviness of the normal Subjects):

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();
        });
}
诗笺 2024-10-27 13:13:48

编辑 - 使用 TimeInterval() 代替。

Zip() 和 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));
}

Edit - Use TimeInterval() instead.

The Zip() and Timestamp() operators might be a good start.

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);

Probably best to test this via the test scheduler, so you know exactly what you're getting:

[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));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文