Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 反应式扩展(Rx)-仅在按下键时订阅鼠标位置数据_Wpf_Events_System.reactive - Fatal编程技术网

Wpf 反应式扩展(Rx)-仅在按下键时订阅鼠标位置数据

Wpf 反应式扩展(Rx)-仅在按下键时订阅鼠标位置数据,wpf,events,system.reactive,Wpf,Events,System.reactive,在WPF中,我只想在按下键时订阅鼠标位置点。然后,我只想在释放关键点时(即,当我有完整的捕获点集时)将捕获的点设置到属性上,并继续侦听下一个向下/向上组合键,以创建另一个鼠标位置捕获,等等 我对上面的解释是,我需要在按键按下时触发一个序列,在按键释放时停止执行,但我希望OnNext接收一组鼠标点 通过大量的阅读(我是Rx新手),我总结了以下伪/实样本: var keyDownSeq = Observable.FromEvent(...); var keyUpSeq = Observable.Fr

在WPF中,我只想在按下键时订阅鼠标位置点。然后,我只想在释放关键点时(即,当我有完整的捕获点集时)将捕获的点设置到属性上,并继续侦听下一个向下/向上组合键,以创建另一个鼠标位置捕获,等等

我对上面的解释是,我需要在按键按下时触发一个序列,在按键释放时停止执行,但我希望OnNext接收一组鼠标点

通过大量的阅读(我是Rx新手),我总结了以下伪/实样本:

var keyDownSeq = Observable.FromEvent(...);
var keyUpSeq = Observable.FromEvent(...);
var mouseMoveSeq = Observable.FromEvent(...);

var mouseMovesWhileKeyDown = keyDownSeq
    .Where(keyEventArgs => keyEventArgs.IsRepeat == false) //WPF fires the same KeyDown repeatedly
    .Where(keyEventArgs => keyEventArgs.Key == Key.Space)
    .Select(_ => mouseMoveSeq
                    .TakeUntil(keyUpSeq)
                    .ToList())
    .Subscribe(listOfMousePoints => MyProperty = listOfMousePoints);
  • 上面的操作是否会像我认为的那样,创建一个按住空格键时遇到的鼠标点列表?我需要在哪里调用ToList(),还是应该在Subscribe中这样做

  • 如果删除第二个Where子句(允许按下任何键开始捕获),如何防止按下第二个或第三个键并在结果序列中导致重复

  • 多谢各位

    编辑

    使用局部变量执行以下操作是否完全不正确

    • 将局部变量设置为Select()中的KeyDown序列值
    • 当KeyUpSeq遇到相同的键时,将局部变量重置为null
    • 过滤KeyDownSeq以忽略此变量有值时的所有值
    • 过滤KeyUpSeq以忽略与局部变量不匹配的所有KeyUp值

    Rx有这样一个局部状态变量的概念吗?

    我认为有两种方法可以简化设置。第一种方法是创建一个
    IObservable
    ,当您的按键在向下或向上位置之间切换时,它会准确地发出信号

    //true means key down, false means key up
    IObservable<bool> keyChange =
        Observable.Merge(
            Observable.FromEvent(/*keyDown*/).Select(_ => true),
            Observable.FromEvent(/*keyUp*/).Select(_ => false))
        .DistinctUntilChanged();
    
    第二种方法是使用
    Observable.Window
    在向下键“窗口打开”和向上键“窗口关闭”之间拉出连续的鼠标移动序列

    IObservable mouseMoves=Observable.FromEvent(…);
    IObservable mousepath=mouseMoves.Window(
    keyChange.Where(b=>b),
    _=>keyChange.Where(b=>!b));
    
    所用方法的文件:


    窗口的签名一开始可能有点吓人,但一旦你理解了它,它的使用就相当简单了。

    你必须小心这里的比赛条件。

    有一些设置

    IObservable<Unit> keyDown = Observable.FromEvent(/*keydown*/).Select(_=>true);
    IObservable<Unit> keyUp = Observable.FromEvent(/*keyup*/).Select(_=>false);
    
    IObservable<Point> mouseMoves = Observable.FromEvent(...);
    
    使用此可观察对象创建窗口

    IOBservable<IObservable<Point> mousePaths = 
        mouseMoves
           .Window(keys)
           .Where((_,i)=>i%2==0);
    
    IOBservablei%2==0);
    
    请注意,我们希望跳过奇数窗口。甚至连窗户都关上了。奇怪的窗户都关上了

    现在没有比赛条件,我们将永远不会错过一个按键或按键事件


    解释如果您使用窗口的另一个重载,即具有单独的打开和关闭触发器的重载,问题在于关闭触发器生成是延迟的。在触发窗口的打开边缘之前,它不会生成,也不会订阅其源。这意味着在窗口关闭触发器注册之前,有一个很小的时间窗口可以发生按键事件。

    谢谢-非常有用,但我有几个问题:1.如何处理两个键被按下,然后一个键被释放的情况?keyChange序列将再次显示false,否?2.我是否正确地认为我可以订阅mousepath,然后在窗口化的IObservable上的OnNext调用ToList(),这样我就可以将我的属性设置为此列表?3.看起来不像,但缓冲区是否有OpeningSelector和ClosingSelector重载?我这样问是因为缓冲区给了我一个我想要的IObservable。@Julius 1。两把钥匙怎么样?我不明白这个问题。也许可以单独制作一个,然后在这里发布链接?2.是的,这正是您对Window的结果所做的。3.缓冲区在这里也可以工作。行为上的区别如下。窗口将在每个窗口启动时发出一个可观察的窗口,每个窗口将在源生成内容时发出其内容。缓冲区将在其末尾发出每个“窗口”,所有窗口都作为列表一次发出。当你想进行批处理时,缓冲区很有用。这里没有竞争条件吗<代码>向下键
    导致窗口打开。调用选择器并
    \u=>keyChange。其中(b=>!b)
    被调用以注册窗口关闭观察值。但是,由于
    keyChange
    是热的,因此在按下键和注册车窗关闭检测之间可能存在一个keyUp事件。基本上,在这种情况下,窗口将保持打开状态。我已经发布了一个正确的答案,下面没有种族条件。我对上述答案的回答是-1,因为我认为如果按原样使用,可能会导致很难发现错误。@BradGonessurfing不恰当地使用downvote。您复制了我的答案,只做了一次修改,很明显,您使用了相同的变量名。我非常感谢你的修改,因为你在这个答案中对问题提出了一个很好的观点,而且我也同意因为这个更正应该将它标记为答案。但我的答案仍然很有用,特别是因为我把提问者带到了解决方案的90%。这里唯一的错误是此
    窗口的细微行为
    重载。SkipUntil将跳过所有值,直到源序列生成true。然后它将永远产生价值。”真,假,真,假,真,假'永远交替。如果您愿意,可以将其解读为
    SkipUntil(value=>value==true)
    在本例中,窗口选择器用于关闭
    和打开
    这就是为什么我们以应该打开它的项开始序列。下一个将关闭它。之后的下一个将打开它,以此类推。链接在这里,但我误读了文件。该方法关闭,然后在发生边界事件时立即打开一个新窗口。修复它很容易。我现在就做。是的,你应该能做到
    
    IObservable<Unit> keyDown = Observable.FromEvent(/*keydown*/).Select(_=>true);
    IObservable<Unit> keyUp = Observable.FromEvent(/*keyup*/).Select(_=>false);
    
    IObservable<Point> mouseMoves = Observable.FromEvent(...);
    
    var keys = keyDown.Merge(keyUp).DistinctUntilChanged().SkipWhile(_=>!_);
    
    IOBservable<IObservable<Point> mousePaths = 
        mouseMoves
           .Window(keys)
           .Where((_,i)=>i%2==0);