使用Rx执行延迟操作一次,取消每个窗口

时间:2012-04-04 14:38:53

标签: .net system.reactive

具体而言,如果按下按键的持续时间大于阈值(T),我会尝试模拟执行动作。

我正在尝试使用Reactive Extensions .NET(稳定的1.0版本)而没有状态变量。

这是我输入的大理石图和我需要的东西:

让T = 3(所以没有关键事件的4 dddd构成了“按下键”)

keyDown: - dddd --- dd - d-dddddddddd ----

keyUp:----------- u ----- u - u --------------- u -

期望:-------- a --------------- a ----------

这是我提出的一些示例代码,它可以使用状态变量。

var keyDownStream = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown").Where(args => args.EventArgs.Key == Key.OemPeriod);
        var keyUpStream = Observable.FromEventPattern<KeyEventArgs>(this, "KeyUp").Where(args => args.EventArgs.Key == Key.OemPeriod);

        var repeatGuard = false;
        keyUpStream.Subscribe(x => repeatGuard = false);
        keyDownStream
            .DelayOrCancel(TimeSpan.FromSeconds(2.0), keyUpStream)
            .Where(_ => repeatGuard == false)
            .Do(_ =>
            {
                repeatGuard = true;
            })
            .Subscribe(
                result =>
                {
                    Console.WriteLine("KeyHold");
                }
            );

public static class JustinsRx
{
    public static IObservable<T> DelayOrCancel<T, TCancel>(this IObservable<T> source,
                                     TimeSpan delay,
                                     IObservable<TCancel> cancel)
    {
        //argument checking skipped
        return from s in source
               from i in Observable.Timer(delay).TakeUntil(cancel)
               select s;
    }
}

2 个答案:

答案 0 :(得分:2)

这样可行,但我觉得它可以缩短。

var firstKeyDowns = Observable
    .Merge(keyDownStream.Select(_ => 'd'), keyUpStream.Select(_ => 'u'))
    .DistinctUntilChanged()
    .Where(c => c == 'd');
var query = from s in firstKeyDowns 
            from i in Observable.Timer(delay).TakeUntil(keyUpStream)
            select s;
编辑:这是一个我认为更好的不同版本:

var noRepeats = Observable
    .Merge(keyDownStream.Select(_ => 'd'), keyUpStream.Select(_ => 'u'))
    .DistinctUntilChanged();
var query = noRepeats
    .Throttle(delay)
    .Where(c => c == 'd');

答案 1 :(得分:1)

这对我有用:

var timer = Observable.Timer(TimeSpan.FromSeconds(1.0));

var query =
    keyDownStream
        .Select(_ =>
            keyUpStream
                .Select(_ => 'u')
                .Amb(timer.Select(_ => 't'))
                .Take(1)
                .Where(x => x == 'u')
                .Select(_ => Unit.Default))
        .Switch();