Gratzy
Gratzy

Reputation: 2908

WPF Left click and drag

I've been trying to work with the mouse event handlers. Using MouseDown only seems to work with the right mouse button. And PreviewMouseLeftButton doesn't activate the MouseMove event until I release the left button.

So this code:

    private void NewButton_MouseDown(object sender, MouseButtonEventArgs e)
    {
        var test = e.LeftButton;
        var test2 = e.RightButton;
        if (!bButtonIsDown)
        {
            bButtonIsDown = true;
            Button mover = (Button)sender;
            pntEnterPoint = e.GetPosition(this.cnvsLinkScreen);

            cnvsLinkScreen.MouseMove += CnvsLinkScreen_MouseMove;
            cnvsLinkScreen.MouseUp += CnvsLinkScreen_MouseUp;
            
            spMover = (StackPanel)((Button)sender).Parent;
            pntPreviousPoint.X = Canvas.GetLeft(spMover);
            pntPreviousPoint.Y = Canvas.GetTop(spMover);

        }
    }

    private void NewButton_MouseMove(object sender, MouseEventArgs e)
    {
        Button mover = (Button)sender;
        StackPanel spMover = (StackPanel)((Button)sender).Parent; 
        base.OnMouseMove(e);
        if (e.LeftButton == MouseButtonState.Pressed)
        {

            // Inititate the drag-and-drop operation.
            FindChild<StackPanel>(cnvsLinkScreen, "CSVImport");
            pntEnterPoint = e.GetPosition(this.cnvsLinkScreen);
            Canvas.SetLeft(spMover, pntEnterPoint.X + 1);
            Canvas.SetTop(spMover, pntEnterPoint.Y + 1);
        }
    }

Works but with right button only. When enabling the event handler with:

newButton.MouseDown += NewButton_MouseDown;

That event handler will not get touched with the left mouse button, which I think is odd.

I've done a good amount of reading out there and people refer to thePreviewMouseLeftButtonDown event handler but when I use that in place (same code) the cnvsLinkScreen.MouseMove += CnvsLinkScreen_MouseMove doesn't fire until I let go of the left mouse button (button up) then the StackPanel drags until I click and drop it.

I set breakpoints and see that the event handler is getting set, but it's just not working until after the left button is released. Clearly I'm missing something with the event handlers on this.

Why isn't the MouseDown event handler not even firing with a left mouse button down; only a right mouse button down?

Upvotes: 0

Views: 1778

Answers (1)

Keith Stein
Keith Stein

Reputation: 6724

This has to do with Routed Events. Unlike with normal events, a routed event can be marked as handled, after which no further handlers for that event will be called.

MouseDown and MouseMove are bubbling routed events, meaning they start at the deepest elements (the ones inside the button) and then "bubble" their way up, through their parents, toward the Window. Any parent can register a handler for these events and it will be called when the event reaches that parent's level. However if any child marks the event as handled, the event will never reach the parent and the parent's handler will never be called.

This is what's happening here. Button has a handler for MouseDown internally. When Button decides it has been clicked, it raises its own Click event and marks MouseDown as handled. Button also seems to handle MouseMove, but only while a click is in progress. This is why your event handlers don't get called during a left-click, because left-click triggers a "click" which ends up handling those events before they make it out of the Button.

PreviewMouseDown and PreviewMouseMove, on the other hand, are both tunneling routed events, meaning they start from the broadest parent (the Window) and work their way inwards toward the exact point of the cursor. Tunneling events happen before bubbling events; the mouse input first tunnels in toward the cursor, then bubbles back up.

If you attach event handlers to PreviewMouseDown and PreviewMouseMove instead of MouseDown and MouseMove, you will see all the mouse input you expect.

Funny side note: you can actually play the same trick on Button that Button is playing on you. If you mark PreviewMouseDown as handled before it gets inside the Button, then it will never raise its Click event.

Upvotes: 2

Related Questions