17

I have to handle both the single click and the double click of a button in a WPF application with different reaction. Unfortunately, on a doubleclick, WPF fires two click event and a double click event, so it's hard to handle this situation.

It tried to solve it using a timer but without success...I hope you can help me.

Lets see the code:

private void delayedBtnClick(object statInfo)
{
    if (doubleClickTimer != null)
        doubleClickTimer.Dispose();
    doubleClickTimer = null;

    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new VoidDelegate(delegate()
    {
        // ... DO THE SINGLE CLICK ACTION
    }));
}

private void btn_Click(object sender, RoutedEventArgs e)
{
    if (doubleClickTimer == null)
        doubleClickTimer = new Timer(delayedBtnClick, null, System.Windows.Forms.SystemInformation.DoubleClickTime, Timeout.Infinite);
        }
    }
}

private void btnNext_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    if (doubleClickTimer != null)
        doubleClickTimer.Change(Timeout.Infinite, Timeout.Infinite);    // disable it - I've tried it with and without this line
        doubleClickTimer.Dispose();
    doubleClickTimer = null;

    //.... DO THE DOUBLE CLICK ACTION
}

The problem is that the 'SINGLE CLICK ACTION' called after the 'DOUBLE CLICK ACTION' on doubleclick. It's strange that I set thedoubleClickTimer to null on double click but in the delayedBtnClick it's true :O

I've already tried to use longer time, a bool flag and lock...

Do you have any ideas?

Best!

Noctis
  • 11,507
  • 3
  • 43
  • 82
Hunsoul
  • 175
  • 1
  • 1
  • 6

2 Answers2

17

If you set the RoutedEvent's e.Handled to true after handling the MouseDoubleClick event then it will not call the Click Event the second time after the MouseDoubleClick.

There's a recent post which touches on having different behaviors for SingleClick and DoubleClick which may be useful.

However, if you are sure you want separate behaviors and want/need to block the first Click as well as the second Click, you can use the DispatcherTimer like you were.

private static DispatcherTimer myClickWaitTimer = 
    new DispatcherTimer(
        new TimeSpan(0, 0, 0, 1), 
        DispatcherPriority.Background, 
        mouseWaitTimer_Tick, 
        Dispatcher.CurrentDispatcher);

private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    // Stop the timer from ticking.
    myClickWaitTimer.Stop();

    Trace.WriteLine("Double Click");
    e.Handled = true;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    myClickWaitTimer.Start();
}

private static void mouseWaitTimer_Tick(object sender, EventArgs e)
{
    myClickWaitTimer.Stop();

    // Handle Single Click Actions
    Trace.WriteLine("Single Click");
}
Community
  • 1
  • 1
rmoore
  • 15,162
  • 4
  • 59
  • 59
  • Thank you very much! The e.Handled = true was the trick! Thank you again for the fast reaction :) – Hunsoul Jun 10 '09 at 08:14
  • 1
    If you use that constructor for DispatcherTimer the timer starts immediately which will cause one spurious single click event. Also Background and Current are default values so confuse things a bit (thought there might be some voodoo going on there!). Very useful though - cheers! – JonnyRaa Jan 16 '13 at 16:55
  • I don't see usage of the DoubleClickTime in the code. Instead I see a hard-coded delay. Is it normal? – SandRock Jan 30 '13 at 09:47
  • 1
    If anyone is looking for a custom behavior which allows a single click and double click commands to be set on an element please see [this code sample](https://code.msdn.microsoft.com/WPF-multiclick-behavior-bb9ee00b) (it takes a similar timer based approach waiting to see if there is a second click within the SystemInformation.DoubleClickTime), – JayChase Jan 05 '16 at 11:44
7

You could try this:

Button.MouseLeftButtonDown += Button_MouseLeftButtonDown;

private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    e.Handled = true;

    if (e.ClickCount > 1)
    {
        // Do double-click code
    }

    else
    {
        // Do single-click code
    }
}

If neccessary, you could require mouse click and wait until mouse up to perform the action.

Josh G
  • 14,068
  • 7
  • 62
  • 74
  • Thanks for your answer! I haven't tried it because the first recommendation solved my problem - but thank you again! :) – Hunsoul Jun 10 '09 at 08:16
  • 3
    I tried this and it works great. Hope this comment will be helpful for others. Thanks Josh. – akjoshi Jul 12 '10 at 10:08
  • 1
    This will not impede the FIRST single click event, because for the first click event e.ClickCount = 1. – Knasterbax Jun 12 '13 at 09:10
  • How should this work at all? The event is fired after the first mouse down happens. No matter what you do afterwards, e.ClickCount will always be 1. WPF on C# – user2799180 Jun 15 '18 at 11:57
  • Isn't recommended to compute click before mouse up, because you prevent user to cancel the click. – Skarllot May 16 '20 at 11:08