2012-05-20 61 views
2

所以我可以嘗試反應性擴展,我想創建一個由用戶按下的鍵的IObservable。我怎樣才能做到這一點?IObservable的按鍵

這是一個C#控制檯應用程序

回答

4

試試這個讓讀鍵可觀察到的序列:

 IObservable<System.ConsoleKeyInfo> keys = 
      Observable 
       .Defer(() => 
        Observable 
         .Start(() => 
          Console.ReadKey())) 
       .Repeat(); 

我測試這和它的工作就像一種享受。

+0

如果我訂閱了兩個處理程序,只有其中一個處理每個事件(隨機,每個事件)。這不是我所期望的,我期望這兩個處理程序每​​個接收每個事件 –

+0

'keys.Subscribe(x => Console.Write(「1」,x.Key)); keys.Subscribe(x => Console.Write (「0」,x.Key)); Thread.Sleep(-1);'然後鍵入'abc'我看到「a1b1c0」而不是「a1a0b1b0c0c1」 –

+0

更正:而不是a10b10c01 –

0

我看不到任何方式如何異步讀取按鍵,所以我認爲你必須在一個單獨的線程使用同步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; 
} 
0

從@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(); 
3

ReadKey的阻塞版本()有一個問題,因爲如果你處理訂閱,它仍然會提示你按下一個鍵。

如果您想要取消訂閱,即可以取消提示,那麼(不幸的是)需要使用輪詢方法。

Observable.Interval(TimeSpan.FromMilliseconds(100)) 
      .Where(_ => Console.KeyAvailable) 
      .Select(_ => (char)Console.ReadKey(false).Key) 

你現在可以做很酷的事情像這個Amb流與Observable.Timer設置爲按鍵超時。