在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(),还是应该在订阅中调用它?
如果删除第二个Where子句(允许按下任意键以开始捕获),如何防止按下第二个或第三个键并导致结果序列重复?


谢谢。

编辑

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


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


Rx是否具有这样的局部状态变量的概念?

最佳答案

您必须在这里注意比赛条件。

进行一些设置。

IObservable<Unit> keyDown = Observable.FromEvent(/*keydown*/).Select(_=>true);
IObservable<Unit> keyUp = Observable.FromEvent(/*keyup*/).Select(_=>false);

IObservable<Point> mouseMoves = Observable.FromEvent(...);


现在创建一个我们将以keyDown事件开始的可观察对象

var keys = keyDown.Merge(keyUp).DistinctUntilChanged().SkipWhile(_=>!_);


使用此可观察对象创建一个窗口。

IOBservable<IObservable<Point> mousePaths =
    mouseMoves
       .Window(keys)
       .Where((_,i)=>i%2==0);


请注意,我们要跳过奇数个窗口。甚至窗户都是关键。奇怪的窗口是关键。

现在没有任何竞争条件,我们将永远不会错过keyDown或keyUp事件。

说明-如果您使用Window的另一个重载,即具有单独的打开和关闭触发器的重载,则问题在于关闭触发器的生成是延迟的。它不会生成,并且在触发窗口的打开边缘之前不会订阅它的源。这意味着在注册关闭窗口触发器之前,keyUp事件发生的时间窗口很小。

关于wpf - react 性扩展(Rx)-仅在按住某个键时订阅鼠标位置数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21886674/

10-09 19:01