Использование Reactive Extension для определенных последовательностей KeyPress? - PullRequest
2 голосов
/ 17 августа 2010

Я новичок .. или точнее .. никогда не использовал RX, поэтому мне было интересно, смогу ли я использовать его в этой ситуации: я хочу добавить в приложение своего рода функциональность Resharper Live Templates, которая позволяет пользователям вводить короткие последовательности символов, за которыми следует [Tab], и мое приложение заменит ранее введенные символы на указанный в другом месте полный текст.

Теперь у меня есть список массивов символов, каждый из которых представляет одну возможную последовательность. Мне нужны какие-то стоп-слова / клавиши, которые разрывают цепочку (например, пробел). У меня есть событие, которое вызывается на каждом KeyPress в моем приложении, теперь (как) я могу использовать RX, чтобы наблюдать это событие и проверить по этому вышеупомянутому списку, была ли выполнена одна из последовательностей и, наконец, была нажата [Tab]?

1 Ответ

3 голосов
/ 08 декабря 2010

Не знаю, слишком ли поздно, но у меня есть для вас ответ.

Нужно использовать метод расширения Rx BufferWithCount.

Я предполагаю, что вы знаете, как превратить события нажатия клавиш в IObservable<char>.

Итак, у вас есть список последовательностей символов, которые вы хотите обнаружить, а затем выполнить действие, которое я предлагаю использовать Dictionary<string, Action> для хранения этих данных, например:

var matches = new Dictionary<string, Action>()
{
    { "ba", () => Console.WriteLine("ba") },
    { "aba", () => Console.WriteLine("aba") },
    { "baa", () => Console.WriteLine("baa") },
    { "abc\t", () => Console.WriteLine("abc\\t") },
};

Итак, вот требуемые запросы Rx (и IEnumerable):

int max =
    matches
    .Select(m => m.Key.Length)
    .Max();

IObservable<string> chords =
    Enumerable
    .Range(2, max - 1)
    .Select(n => keys
        .BufferWithCount(n, 1)
        .Select(cs => new string(cs.ToArray())))
    .Merge();

IObservable<Action> actions =
    chords
    .Where(s => matches.ContainsKey(s))
    .Select(s => matches[s]);

Итак, наконец, у вас есть IObservable<Action>, на который вы можете подписаться, и вы просто вызываете Action.

Если вы хотите проверить, что это работает, используйте следующий код:

IConnectableObservable<char> keys = "ababc\tdabaababc\tebad"
    .ToObservable()
    .Publish();
//`.Publish()` makes a cold observable become hot,
// but you must call `Connect()` to start producing values.

//insert above `matches` definition here.
//insert above queries here.

actions.Subscribe(a => a());

keys.Connect();

Результат должен быть:

ba
aba
abc\t
ba
aba
baa
ba
aba
abc\t
ba

Наслаждайтесь!

...