Search code examples
c#winformsmousedown

MouseDown and Click conflict


I have a Drag() method on form_MouseDown event. I also have a click event on the form. The problem is that if I click on the form, MouseDown event gets triggered and it never gets the chance to trigger click event.

What is the best way to solve this issue? I was thinking counting pixels if the form is actually dragged, but there has to be a better way. Any suggestions?


Solution

  • I was thinking counting pixels if the form is actually dragged, but there has to be a better way.

    Nope, that's exactly how you have to do it.

    This isn't just a software limitation; it's very much a practical one as well. If you think through the problem from a user's perspective, you'll immediately see the problem as well as the solution. Ask yourself, what is the difference between a click and a drag?

    Both of them start with the mouse button going down over the object, but one of them ends with the mouse button going back up over the object in the same position and the other one ends with the mouse button going back up in a completely different position.

    Since time machines haven't been perfected yet, you have no way of knowing this in advance.

    So yes, you need to maintain some kind of a distance threshold, and if the pointer moves outside of that distance threshold while it is down over the object, then you consider it a drag. Otherwise, you consider it a click.

    That distance threshold should not be 0. The user should not be required to hold the mouse completely still in order to initiate a click. A lot of users are sub-par mousers. They are very likely to twitch slightly when trying to click. If the threshold is 0, they'll end up doing a lot of inadvertent dragging when they try to click.

    Of course, you don't actually have to worry about any of this or compute the drag threshold yourself. Instead, use the Windows default values, obtainable by calling the GetSystemMetrics function and specifying either SM_CXDRAG or SM_CYDRAG. (These might be exposed somewhere by the WinForms framework, but I don't think so. It's just as easy to P/Invoke them yourself.)

    const int SM_CXDRAG = 68;
    const int SM_CYDRAG = 69;
    [DllImport("user32.dll")]
    static extern int GetSystemMetrics(int index);
    
    Point GetDragThreshold()
    {
        return new Point(GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
    }
    

    In the field of UX/UI, this sort of thing is called hysteresis or debouncing, by analogy to the use of these terms in physics and electronics.