RX - 仅在主题符合条件时运行代码

时间:2012-05-07 00:06:36

标签: c# system.reactive

我正在使用observable来处理keydown事件。 我想发布一个observable,它总是设置关键,以处理消费者实际处理它的 iff 。 这可能吗?

以下是我现在处理密钥的示例:

KeyDown.Where(e => e.Key == Keys.W)
.Subscribe(e => { Console.WriteLine(e.Key); e.Handled = true; });

以下是我想要做的一个例子(如果之后自动设置处理属性,我也可以发布Keys而不是KeyDownEventArgs):

HandledKeyDown.Where(k => k == Keys.W).Subscribe(k => Console.WriteLine(k));

这是我试过的:

HandledKeyDown = Observable.Create<Key>(observer => {
    var keys = KeyDown.Subscribe(e => { e.Handled = true; observer.OnNext(e.Key); });
    return () => keys.Dispose();
});

此代码的问题在于,无论消费者是否实际处理了密钥,密钥都将始终设置为已处理。

有没有办法知道代码是否“已达到”订阅方法?

2 个答案:

答案 0 :(得分:1)

您希望在KeyEventArgs上超载订阅,以便在订阅后处理事件。听起来像是一个扩展名:

public static IDisposable SubscribeAndHandle(this IObservable<KeyEventArgs> input, Action<Keys> action)
{
    return input.Subscribe(e => { action(e.KeyCode); e.Handled = true; });
}

然后,您只需使用SubscribeAndHandle代替Subscribe,只有在操作完成后才会将Handled设置为true,并且操作可以使用Keys而不是KeyEventArgs {1}}:

var sub = KeyDown
          .Where(e => e.KeyCode = Keys.W) // and so on
          .SubscribeAndHandle(k => Console.WriteLine(k));

请注意,如果您不介意在执行操作之前将Do设置为true,则可以在扩展方法中使用Handled。这是一种更清晰的运行副作用的方法:

public static IDisposable SubscribeAndHandle(this IObservable<KeyEventArgs> input, Action<Keys> action)
{
    return input.Do(e => e.Handled = true)
                .Select(e => e.KeyCode)
                .Subscribe(e => action(e));
}

来自@Enigmativity的有用评论表明,或许您可能想要在订阅中决定Handled是否设置为true。这很简单,只需将扩展方法更改为接受Func<Keys,bool>而不是Action<Keys>

public static IDisposable SubscribeAndHandle(this IObservable<KeyEventArgs> input, Func<Keys,bool> action)
{
    return input.Subscribe(e => e.Handled = action(e.KeyCode));
}

答案 1 :(得分:0)

我会考虑做这样的事情:

var HandledKeyDown =
    KeyDown
        .Do(e => { /* Handling Code Here */ })
        .Where(e => e.Handled)
        .Where(e => e.Key == Keys.W)
        .Select(e => e.Key)
        .Subscribe(k => Console.WriteLine(k));

Do扩展方法可让您“拦截”可观察内联的值。

如果有帮助,请告诉我。