[英]What is the proper way to determine the end of a mouse drag using Rx?
我正在慢慢学习如何在WPF中使用.NET的Reactive Extensions 。 有一些关于编写拖放或绘制例程有多么简单的初学者示例,但是它们都非常简单。 我正在尝试更进一步,“正确”的方式对我来说并不明显。
所有示例都展示了如何定义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");
然后如何在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)
),然后执行一些操作吗?
该序列永远不会完成,因为源(MouseDown)永远不会完成(这是一个事件)。 值得指出的是, IObservable
不能多次调用订户的OnComplete
,它是合同的一部分( OnNext* (OnCompleted|OnError)?
)。
要找出mouseMove.TakeUntil(mouseUp)
序列何时完成,您需要加入对SelectMany
的调用:
public static IDisposable TrackDrag(this UIElement element,
Action<Rect> dragging, Action dragComplete)
{
var mouseDown = Observable.FromEvent(...);
var mouseMove = Observable.FromEvent(...);
var mouseUp = Observable.FromEvent(...);
return (from start in mouseDown
from currentPosition in mouseMove.TakeUntil(mouseUp)
.Do(_ => {}, () => dragComplete())
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));
).Subscribe(dragging);
}
然后,您可以像这样使用它:
element.TrackDrag(
rect => { },
() => {}
);
为了清楚起见,这是使用基础扩展方法的LINQ表达式:
return mouseDown.SelectMany(start =>
{
return mouseMove
.TakeUntil(mouseUp)
.Do(_ => {}, () => dragComplete())
.Select(currentPosition => new Rect(...));
})
.Subscribe(dragging);
也就是说,对于mouseDown中的每个值,将预订一个新序列。 该序列完成后,请调用dragComplete()。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.