Создание перетаскивания мышью осуществляется с помощью Reactive Extensions - PullRequest
1 голос
/ 23 апреля 2010

У меня есть следующее

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 };

, который, когда я подпишусь на него, даст мне начальную точку перетаскивания и текущую конечную точку. Теперь мне нужно что-то сделать, как только перетаскивание сделано. Я безуспешно пытался сделать это полностью с RX и в итоге сделал

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

leftMouseUp.Subscribe(e=>
    {
        if(dragging)
        {
            MessageBox.Show("Just finished dragging");
            dragging = false;
        }
    });

Это прекрасно работает, пока я не сделаю перетаскивание правой кнопкой мыши. Затем, когда я нажимаю левую кнопку мыши, я получаю окно сообщения. Если я только перетаскиваю левую кнопку, я получаю окно сообщения, а затем щелчок левой кнопкой мыши не создает окно. Я хотел бы сделать это без внешнего состояния, но если бы не что-то еще, я бы хотя бы хотел, чтобы оно работало должным образом.

К вашему сведению: я пытался сделать волатильное перетаскивание и использовать блокировку, но это не сработало.

EDIT

Оказывается, моя проблема была в контекстном меню, вызываемом правой кнопкой мыши. Однажды я избавился от этого, мой вышеприведенный код сработал. Итак, теперь моя проблема в том, как мне получить контекстное меню и при этом работать с моим кодом. Я предполагаю, что контекстное меню обрабатывало щелчок левой кнопкой мыши, и это как-то приводило к тому, что мой код не работал, но я все еще ломаю голову над ним.

1 Ответ

5 голосов
/ 25 апреля 2010

Если перетаскивание - это все, что вам нужно, не будет ли простой .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));

Вы можете применить фильтр Где, если вам нужно исключить перетаскивание нулевой длины.

Редактировать: хотя Zip был бы уязвим для освобождения мыши за пределами окна - в этом случае, вы не получите mouseUp, если не захватите ... Вот версия, которая использует только последнюю версию mouseDown до mouseUp:

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();
...