0

我正在使用 observables 来处理 keydown 事件。我想发布一个可观察的,如果消费者实际处理了它,它将始终设置要处理的密钥。这可能吗?

这是我现在如何设置键的示例:

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

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

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

4

2 回答 2

1

您想要的是重载订阅,KeyEventArgs以便在订阅后处理事件。听起来像一个扩展:

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

然后你只需使用SubscribeAndHandleinstead of Subscribe,它只会在动作运行后设置Handled为 true ,并且动作可以使用Keysnot KeyEventArgs

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

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

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。这很简单,只需将扩展方法更改为接受 aFunc<Keys,bool>而不是 a Action<Keys>

public static IDisposable SubscribeAndHandle(this IObservable<KeyEventArgs> input, Func<Keys,bool> action)
{
    return input.Subscribe(e => e.Handled = action(e.KeyCode));
}
于 2012-05-07T04:43:31.970 回答
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拦截”可观察内联的值。

让我知道这是否有帮助。

于 2012-05-07T00:17:50.627 回答