2012-04-04 3 views
1

具体的には、しきい値(T)を超えるキーが押された場合に動作をシミュレートしようとしています。Rxを使用して各ウィンドウの取り消しを伴う遅延アクションを1回実行します。

私はReactive Extensions .NET(安定版1.0)を使用して状態変数を使用してこれを実行しようとしています。

は、ここに私の入力の大理石の図だと私は必要なもの:

KeyDownイベントを( "押したままキー" を構成するキーアップイベントなしSO 4 DDDD)T = 3を聞かせて: - -dddd --- dd-d-dddddddddd -----

keyUp:----------- u ----- u - u -------- ------- u--

希望:-------- a --------------- a --------- -

これは私が思いついたコードの例ですが、状態変数を使います。

var keyDownStream = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown").Where(args => args.EventArgs.Key == Key.OemPeriod); 
     var keyUpStream = Observable.FromEventPattern<KeyEventArgs>(this, "KeyUp").Where(args => args.EventArgs.Key == Key.OemPeriod); 

     var repeatGuard = false; 
     keyUpStream.Subscribe(x => repeatGuard = false); 
     keyDownStream 
      .DelayOrCancel(TimeSpan.FromSeconds(2.0), keyUpStream) 
      .Where(_ => repeatGuard == false) 
      .Do(_ => 
      { 
       repeatGuard = true; 
      }) 
      .Subscribe(
       result => 
       { 
        Console.WriteLine("KeyHold"); 
       } 
      ); 

public static class JustinsRx 
{ 
    public static IObservable<T> DelayOrCancel<T, TCancel>(this IObservable<T> source, 
            TimeSpan delay, 
            IObservable<TCancel> cancel) 
    { 
     //argument checking skipped 
     return from s in source 
       from i in Observable.Timer(delay).TakeUntil(cancel) 
       select s; 
    } 
} 
+0

進捗アップデート:私はこのクエリをしようとするんだけど、それは実際には、呼び出し元をブロックしています!誰もがなぜこれが呼び出し元をブロックしているので、ウィンドウが表示されないように知っていますか? keyDownStream .DelayOrCancel(TimeSpan.FromSeconds(2)、keyUpStream) .Window(()=> keyUpStream) .Subscribe(結果=> { IF(result.First()== result.Last() ) Console.WriteLine( "KeyHold"); //操作を行う }); – Mooser

答えて

2

これは動作しますが、私はそれを短くすることができることを感じます。

var firstKeyDowns = Observable 
    .Merge(keyDownStream.Select(_ => 'd'), keyUpStream.Select(_ => 'u')) 
    .DistinctUntilChanged() 
    .Where(c => c == 'd'); 
var query = from s in firstKeyDowns 
      from i in Observable.Timer(delay).TakeUntil(keyUpStream) 
      select s; 

編集:ここで私は少しよりよいと思い異なるバージョンです:

var noRepeats = Observable 
    .Merge(keyDownStream.Select(_ => 'd'), keyUpStream.Select(_ => 'u')) 
    .DistinctUntilChanged(); 
var query = noRepeats 
    .Throttle(delay) 
    .Where(c => c == 'd'); 
+0

+1これはおそらく、 DelayOrCancelに渡す前に、[AlternatingSubject](http://stackoverflow.com/a/9445579/174594)のような入力フィルタリングを行うことができます。 –

+0

Thanks Matthew、私はあなたとEnigmativityのソリューションを見てみましょう。そして、私の大理石の図/コードの例と同じように実際に問題を解決してくれた方には、正解をお寄せください。 – Mooser

+0

優秀な人、DistinctUntilChangedの使用により、私のステートフルコードよりもはるかに優れた性能を発揮することがわかります。 – Mooser

1

これが私の仕事:

var timer = Observable.Timer(TimeSpan.FromSeconds(1.0)); 

var query = 
    keyDownStream 
     .Select(_ => 
      keyUpStream 
       .Select(_ => 'u') 
       .Amb(timer.Select(_ => 't')) 
       .Take(1) 
       .Where(x => x == 'u') 
       .Select(_ => Unit.Default)) 
     .Switch(); 
+0

これは近くに来ていません:) – Mooser

+0

@JustinMoser - どのようにそうですか?それは要件を満たしているようだった。何がうまくいかなかったか教えていただけますか? – Enigmativity

+0

申し訳ありません私はそれがコンパイルされていないので、あなたがそれをテストしたとは思わなかった。理由は、 "Where(x => x == 'u')"のために、KeyUpイベントが発生するまでOnNextが発生しないためです。このクエリを修正することは簡単なことではありません。 (どこから削除することはできません。なぜなら、OnNextがすべてのkeyDownイベントに対してトリガーするなど、他の問題があるからです。 – Mooser