过滤一个Touch.FrameReported的IObservable使用随时间变化

过滤一个Touch.FrameReported的IObservable使用随时间变化

问题描述:

我已经在Windows Phone 7的无功扩展(RX)玩耍,我非常接近一个有效的解决方案,但被抓住了一个小细节任意布尔条件。我试图用Touch.FrameReportedObservable.FromEvent(有点教育追求的学习触摸API和RX更好)处理原始触摸事件,但我只想处理在一定条件下的事件。例如,我可能想要过滤订阅,只有在透视控件中选择了特定页面时才触及事件,但它可能是任意条件,在true和false之间来回切换。由于条件是一个随时间而变化的值,因此它感觉应该是另一个可以与触摸事件流合并的可观察值,但是我不知道该怎么做。过滤一个Touch.FrameReported的IObservable使用随时间变化

相反,我有一个半工作解决方案,使用IObservable的TakeWhileSkipUntil扩展名。我有收到全部为整个应用程序(oTouchApp),第二流,只有需要的项目,而我的过滤条件为真(oTouchPage)的触摸事件,然后其他两个流的触摸过滤成触摸下一个流(oTouchDown)并修改(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");}); 

UPDATE: 原来所有我需要的是增加一个简单的where子句到oTouchPage流:var oTouchPage = oTouchApp.Where((x) => TestCondition == True); 它可能不是最好的解决方案,由于TestCondition是一个项目产生的每个时刻评价,但它运行良好,易于阅读。如果测试条件基于事件或其他易于转换为IObservable的条件,那么我认为下面提到的Window或SelectMany方法可能会更好,但是您可能需要处理“Stream of Stream”。我现在正在与related question战斗。

TakeWhile当谓词返回false时触发完成,此时所有内容都被拆除。

你有两个选择:

最简单的解决方案是使用Repeat再次启动的整个过程:

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

另一个解决办法是使用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); 

除了Richard Szalays的回答,您还可以查看Window运营商(尽管我认为他的第二个解决方案可能是正确的)。你有时间窗口,你想接受触摸事件。

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)); 
} 
+0

Window运算符看起来像是exactl Ÿ我需要什么,但我对它的用法有点困惑。它返回IObserbles的IObservable,我只想要一个只在TestCondition == True时才产生的流。有没有办法将“顺序流的流”合并为一个可以在oTouchDown/oTouchUp中使用的流?还有什么地方可以找到Window操作符的更多信息或示例?所有我能找到的是http://blogs.msdn.com/b/rxteam/archive/2010/12/25/rx-christmas-release-2010-introducing-join-and-groupjoin-operators-and-more.aspx – 2011-01-29 23:54:51

+0

从Channel 9找到了一个关于Window运算符的精彩视频。没有任何实际的例子,但有助于概念化。开始大约30分钟,但整个视频很好观看:http://channel9.msdn.com/Shows/Going+Deep/Programming-Streams-of-一致性--with-Join-and-GroupJoin-for-Rx – 2011-01-30 10:38:53