繁体   English   中英

使用Rx确定鼠标拖动结束的正确方法是什么?

[英]What is the proper way to determine the end of a mouse drag using Rx?

我正在慢慢学习如何在WPF中使用.NET的Reactive Extensions 有一些关于编写拖放或绘制例程有多么简单的初学者示例,但是它们都非常简单。 我正在尝试更进一步,“正确”的方式对我来说并不明显。

所有示例都展示了如何定义MouseDownMouseMoveMouseUp的事件流。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM