使用Reactive Extensions创建可观察的鼠标拖动

juh*_*arr 1 c# system.reactive

我有以下内容

var leftMouseDown = Observable.FromEvent<MouseButtonEventArgs>(displayCanvas, "MouseLeftButtonDown");
var leftMouseUp = Observable.FromEvent<MouseButtonEventArgs>(displayCanvas, "MouseLeftButtonUp");
var mouseMove = Observable.FromEvent<MouseEventArgs>(displayCanvas, "MouseMove");

var leftMouseDragging = from down in leftMouseDown
                        let startPoint = down.EventArgs.GetPosition(displayCanvas)
                        from move in mouseMove.TakeUntil(leftMouseUp)
                        let endPoint = move.EventArgs.GetPosition(displayCanvas)
                        select new { Start = startPoint, End = endPoint };
Run Code Online (Sandbox Code Playgroud)

当我订阅它时,它会给我拖动的起点和当前的终点.现在我需要在拖动完成后做一些事情.我试图用RX完全做到这一点并没有成功,最终做到了

leftMouseDragging.Subscribe(value=>
    {
        dragging = true;
        //Some other code
    });

leftMouseUp.Subscribe(e=>
    {
        if(dragging)
        {
            MessageBox.Show("Just finished dragging");
            dragging = false;
        }
    });
Run Code Online (Sandbox Code Playgroud)

这工作正常,直到我拖动鼠标右键.然后,当我单击鼠标左键时,我会看到消息框.如果我只做一个左键拖动我得到消息框,然后单击鼠标左键不会产生该框.我想在没有外部状态的情况下这样做,但如果没有别的,我至少希望它能正常工作.

仅供参考:我尝试拖动易失性并使用锁定,但这不起作用.

编辑

事实证明我的问题是右键单击上下文菜单.一旦我摆脱了我的上述代码工作.所以,现在我的问题是如何获得上下文菜单并仍然使我的代码工作.我假设上下文菜单处理鼠标左键并且不知何故导致我的代码不起作用,但我仍然困惑不解.

Ser*_*hov 5

如果只需要拖动,那么简单的.Zip不会起作用吗?:

var drag = _mouseDown
    .Select(args => args.EventArgs.GetPosition(canvas))
    .Zip(_mouseUp.Select(args => args.EventArgs.GetPosition(canvas)), 
        (p1, p2) => new { p1, p2 });
drag.Subscribe(p1p2 => 
        Console.WriteLine(@"({0}:{1})({2}:{3})", 
            p1p2.p1.X, p1p2.p1.Y, p1p2.p2.X, p1p2.p2.Y));
Run Code Online (Sandbox Code Playgroud)

如果需要排除零长度拖动,可以应用Where过滤器.

编辑:虽然,Zip很容易在窗口外释放鼠标 - 在这种情况下,除非你捕获,否则你不会得到mouseUp ...这是在mouseUp之前只使用最新mouseDown的版本:

var drag = _mouseDown
    .Select(args => args.EventArgs.GetPosition(canvas))
    .TakeUntil(_mouseUp)
    .CombineLatest(_mouseUp
        .Select(args => args.EventArgs.GetPosition(canvas))
        .Take(1), (p1, p2) => new { p1, p2 })
    .Repeat();
Run Code Online (Sandbox Code Playgroud)