在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/