Итак, я могу поэкспериментировать с Reactive Extensions, я бы хотел создать IObservable ключей, нажатых пользователем. Как я могу это сделать?IObservable из нажатых клавиш
Это для C# консольного приложения
Итак, я могу поэкспериментировать с Reactive Extensions, я бы хотел создать IObservable ключей, нажатых пользователем. Как я могу это сделать?IObservable из нажатых клавиш
Это для C# консольного приложения
Попробуйте это, чтобы получить наблюдаемую последовательность клавиш чтения:
IObservable<System.ConsoleKeyInfo> keys =
Observable
.Defer(() =>
Observable
.Start(() =>
Console.ReadKey()))
.Repeat();
Я испытал это, и она работала, как лечить.
Я не вижу способа, как читать нажатия асинхронны, так что я думаю, что вы должны использовать синхронный Console.ReadKey()
в отдельном потоке, наряду с Subject<T>
. Что-то вроде:
IObservable<ConsoleKeyInfo> ObserveKeysUntilEscape()
{
var keys = new Subject<ConsoleKeyInfo>();
Task.Run(
() =>
{
ConsoleKeyInfo key;
do
{
key = Console.ReadKey();
keys.OnNext(key);
} while (key.Key != ConsoleKey.Escape);
keys.OnCompleted();
});
return keys;
}
Альтернативой методу от @svick является то, что петля ReadKey
является Enumerable
и преобразуется в Observable
. Это ставит его в фоновом режиме.
static IEnumerable<ConsoleKeyInfo> KeyPresses()
{
ConsoleKeyInfo key;
do
{
key = Console.ReadKey();
yield return key;
} while (key.Key != ConsoleKey.Escape);
}
Мы можем генерировать наблюдаемые на пул потоков:
var keys = KeyPresses().ToObservable(System.Reactive.Concurrency.Scheduler.ThreadPool);
keys.Subscribe(key => Console.WriteLine("Pressed: {0}", key.Key));
И ждать на основной поток для ключа Escape
:
keys.Where(key => key.Key == ConsoleKey.Escape).First();
Блокирующий версии ReadKey() есть проблема в том, что если вы распоряжаетесь подпиской, она по-прежнему предлагает вам нажать клавишу.
Если вы хотите иметь чистую отмену подписки, то есть сможете отменить приглашение, это (к сожалению) необходимо пройти с помощью опроса.
Observable.Interval(TimeSpan.FromMilliseconds(100))
.Where(_ => Console.KeyAvailable)
.Select(_ => (char)Console.ReadKey(false).Key)
Теперь вы можете делать классные вещи, как Amb
этот поток с Observable.Timer
, чтобы установить тайм-аут для нажатий.
Если я подпишу два обработчика, только один из них обработает каждое событие (случайным образом, для каждого события). Это не то, что я ожидал, я ожидал, что оба обработчика будут получать каждое событие –
'keys.Subscribe (x => Console.Write (" 1 ", x.Key)); keys.Subscribe (x => Console.Write («0», x.Key)); Thread.Sleep (-1); 'then type 'abc' Я вижу« a1b1c0 », а не« a1a0b1b0c0c1 » –
исправление: вместо a10b10c01 –