使用 Rx 确定鼠标拖动结束的正确方法是什么?
我正在慢慢学习如何将 Reactive Extensions for .NET 与 WPF 结合使用。有一些初学者示例说明编写拖放或绘图例程是多么简单,但它们都非常简单。我试图更进一步,但我不清楚什么是“正确”的方法。
这些示例都展示了如何定义来自 MouseDown
、MouseMove
和 MouseUp
的事件流,
var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(..., "MouseDown")
select evt.EventArgs.GetPosition(...);
var mouseMoves = from evt in Observable.FromEvent<MouseEventArgs>(..., "MouseMove")
select evt.EventArgs.GetPosition(...);
var mouseUp = Observable.FromEvent<MouseButtonEventArgs>(..., "MouseUp");
然后如何在 MouseDown
、MouseMove
和 MouseUp
中轻松执行操作code>MouseDrag (这显示从起始拖动点到当前鼠标位置创建的矩形的坐标)
var mouseDrag = from start in mouseDown
from currentPosition in mouseMoves.TakeUntil(mouseUp)
select new Rect(Math.Min(start.X, currentPosition.X),
Math.Min(start.Y, currentPosition.Y),
Math.Abs(start.X - currentPosition.X),
Math.Abs(start.Y - currentPosition.Y));
mouseDrag.Subscribe(x =>
{
Info.Text = x.ToString();
});
我的问题是,在鼠标结束时完成任务的“正确”方法是什么拖?最初,我认为我可以做这样的事情:
mouseDrag.Subscribe(
onNext: x =>
{
Info.Text = x.ToString();
},
onCompleted: () =>
{
// Do stuff here...except it never gets called
});
不过,阅读更多文档,似乎当没有更多数据(永远)并且可以处置对象时,会调用 onCompleted
。
因此,第一个看似合理的选择是订阅 mouseUp 事件并在那里执行某些操作。
mouseUp.Subscribe(x =>
{
// Do stuff here..
}
但此时,我也可以返回使用“正常”MouseLeftButtonUp
事件处理程序。
是否有另一种方法可以确定 mouseDrag 何时“完成”(或 TakeUntil(mouseUp) 何时发生)并执行某些操作?
I am slowly learning how to use Reactive Extensions for .NET with WPF. There a few beginner examples about how simple it is to write drag-drop or drawing routines but they are all extremely simple. I'm trying to go one step further and it's not obvious to me what the "proper" way is.
The examples all show how you can define streams of events from MouseDown
, MouseMove
, and MouseUp
var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(..., "MouseDown")
select evt.EventArgs.GetPosition(...);
var mouseMoves = from evt in Observable.FromEvent<MouseEventArgs>(..., "MouseMove")
select evt.EventArgs.GetPosition(...);
var mouseUp = Observable.FromEvent<MouseButtonEventArgs>(..., "MouseUp");
And then how you can easily do things during a MouseDrag
(this displays the co-ordinates of the rectangle created from the starting drag point to the current mouse position)
var mouseDrag = from start in mouseDown
from currentPosition in mouseMoves.TakeUntil(mouseUp)
select new Rect(Math.Min(start.X, currentPosition.X),
Math.Min(start.Y, currentPosition.Y),
Math.Abs(start.X - currentPosition.X),
Math.Abs(start.Y - currentPosition.Y));
mouseDrag.Subscribe(x =>
{
Info.Text = x.ToString();
});
My question is, what is the "proper" way to accomplish a task at the end of the mouse drag? Originally, I thought I could do something like this:
mouseDrag.Subscribe(
onNext: x =>
{
Info.Text = x.ToString();
},
onCompleted: () =>
{
// Do stuff here...except it never gets called
});
Reading more of the documentation, though, it seems that onCompleted
is called when there is no more data (ever) and when the object can be disposed.
So the first option that seems plausable is subscribing to the mouseUp
event and doing something there.
mouseUp.Subscribe(x =>
{
// Do stuff here..
}
But then at this point, I may as well go back to just use the "normal" MouseLeftButtonUp
event handler.
Is there another way to determine when the mouseDrag
is "completed" (or when the TakeUntil(mouseUp)
) occurs and perform some action then?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
该序列永远不会完成,因为源 (MouseDown) 永远不会完成(它是一个事件)。值得指出的是,
IObservable
不能多次调用订阅者的OnComplete
,它是合约的一部分(OnNext* (OnCompleted|OnError)?
代码>)。要了解
mouseMove.TakeUntil(mouseUp)
序列何时完成,您需要挂钩对SelectMany
的调用:这样使用它:
然后您可以像 为了清楚起见,这里是使用底层扩展方法的 LINQ 表达式:
也就是说,对于 mouseDown 中的每个值,都将订阅一个新序列。当该序列完成时,调用dragComplete()。
The sequence never completes because the source (MouseDown) never completes (it is an event). It's worth pointing out that a
IObservable
cannot callOnComplete
of a subscriber more than once, it's part of the contract (OnNext* (OnCompleted|OnError)?
).To find out when the
mouseMove.TakeUntil(mouseUp)
sequence completes, you'll need to hook into the call toSelectMany
:Then you can use it like so:
For the interest of clarity, here is the LINQ expression using the underlying extension methods:
That is, for each value from mouseDown a new sequence will be subscribed to. When that sequence completes, call dragComplete().