1

私はWindowsPhone7のReactiveExtensions(RX)で遊んでいて、実用的なソリューションに非常に近いですが、1つの小さな詳細に巻き込まれました。Touch.FrameReportedと(Touch APIとRXをよりよく学ぶための少しの教育的な探求)を使用して生のタッチイベントを処理しようとしていますがObservable.FromEvent、特定の条件下でのみイベントを処理したいと思います。たとえば、ピボットコントロールで特定のページが選択されている場合にのみ、タッチダウンイベントとタッチアップイベントへのサブスクリプションをフィルタリングしたい場合がありますが、trueとfalseの間で前後に変化する任意の条件である可能性があります。条件は時間の経過とともに変化する値であるため、タッチイベントストリームとマージされる別のオブザーバブルである必要があるように感じますが、それを行う方法を一生理解することはできません。

代わりに、IObservableの拡張機能を使用TakeWhileした半ば機能するソリューションがあります。SkipUntilアプリ全体のすべてのタッチイベントを受信するストリーム(oTouchApp)、フィルタリング条件がtrueの場合にのみアイテムを取得する2番目のストリーム(oTouchPage)、そしてタッチをタッチダウン(oTouchDown)とタッチアップにフィルタリングする他の2つのストリームがあります。 (oTouchDown)アクション。これらのストリームはすべてタイプIObservable<IEvent<TouchFrameEventArgs>>であるため、簡単にマージして比較し、カスタムジェスチャを作成できます。問題は、フィルター条件がtrueからfalseに変わると、oTouchPageストリームを再起動できないことです。ストリームを手動で再作成する必要がありますが、どういうわけかオンとオフを切り替えることができます。

これが私がこれまでに持っているコードです。ブール値(オン/オフスイッチなど)を使用してストリームをフィルタリングする方法についてのヘルプをいただければ幸いです。

var oTouchApp = Observable.FromEvent<TouchFrameEventHandler, TouchFrameEventArgs>(x => new TouchFrameEventHandler(x), ev => Touch.FrameReported += ev, ev => Touch.FrameReported -= ev);
//This stops working after TestCondition goes from True to False
var oTouchPage = oTouchApp.SkipWhile((x) => TestCondition == False).TakeWhile((x) => TestCondition == True);
var oTouchDown = from t in oTouchPage
                 let primarypoint = t.EventArgs.GetPrimaryTouchPoint(this)
                 where primarypoint.Action == TouchAction.Up
                 select t;
var oTouchUp = from t in oTouchPage
               let primarypoint = t.EventArgs.GetPrimaryTouchPoint(this)
               where primarypoint.Action == TouchAction.Down
               select t;
//Code for testing
var sub1 = oTouchPage.Subscribe(x =>{Debug.WriteLine("TouchPage");});
var sub2 = oTouchDown.Subscribe(x =>{Debug.WriteLine("TouchDown");});
var sub3 = oTouchUp.Subscribe(x =>{Debug.WriteLine("TouchUp");});

更新: 必要なのは、oTouchPageストリームに単純なwhere句を追加するvar oTouchPage = oTouchApp.Where((x) => TestCondition == True); ことだけでした。TestConditionはアイテムが生成されるたびに評価されるため、最善の解決策ではない可能性がありますが、うまく機能し、読みやすいです。テスト条件がイベントまたはIObservableに変換しやすいその他の条件に基づいている場合は、以下で説明するWindowまたはSelectManyのアプローチの方が適していると思いますが、「ストリームのストリーム」を処理する必要がある場合があります。私は今、関連する質問でそれと戦っています。

4

2 に答える 2

2

Richard Szalaysの回答に加えて、オペレーターを調べることもできますWindow(ただし、彼の2番目の解決策はおそらく正しいものだと思います)。タッチイベントを受け取りたい時間枠があります。

private void SetupStream()
{
    Subject<bool> testConditionValues = new Subject<bool>();

    var startTrigger = testConditionValues.DistinctUntilChanged()
         .Where(v => v == true);

    var endTrigger = testConditionValues
         .Where(v => v == false);

    touchEvents.Window(startTrigger, _ => endTrigger)
        .Subscribe(HandleNewWindow);

    // Open window
    testConditionValues.OnNext(true);

    // Close window
    testConditionValues.OnNext(false);

}

public void HandleNewWindow(IObservable<IEvent<EventArgs>> events)
{
    events.Subscribe(mousEvent => Trace.WriteLine(mousEvent));
}
于 2011-01-28T09:15:09.410 に答える
2

TakeWhile述語がfalseを返すと完了をトリガーし、その時点ですべてが破棄されます。

2つの選択肢があります。

最も簡単な解決策はRepeat、プロセス全体を再開するために使用することです。

var oTouchPage = oTouchApp
    .SkipWhile((x) => TestCondition == false)
    .TakeWhile((x) => TestCondition == true)
    .Repeat();

もう1つの解決策は、リスニングの各「ラウンド」の開始をトリガーするために使用して状況を追跡することSelectManyです(これは「ドラッグアンドドロップ」WPF Rxの例と非常によく似ています)。

// Think of Subject like an observable variable
// This can just be an IObservable<bool> if the triggers actually come from elsewhere
Subject<bool> testConditionValues = new Subject<bool>();

var startTrigger = testConditionValues
    .DistinctUntilChanged()
    .Where(v => v == true);

var endTrigger = testConditionValues
    .Where(v => v == false);

var values = from start in startTrigger
             from touch in touchEvents.TakeUntil(endTrigger)
             select touch;

// Start listening
testConditionValues.OnNext(true);

// Stop listening
testConditionValues.OnNext(false);
于 2011-01-28T09:28:52.157 に答える