WPF: Button single click + double click issue
Asked Answered
C

2

18

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!

Cleave answered 9/6, 2009 at 17:33 Comment(0)
C
18

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");
}
Cupel answered 9/6, 2009 at 18:17 Comment(4)
Thank you very much! The e.Handled = true was the trick! Thank you again for the fast reaction :)Cleave
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!Understrapper
I don't see usage of the DoubleClickTime in the code. Instead I see a hard-coded delay. Is it normal?Evelineevelinn
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 (it takes a similar timer based approach waiting to see if there is a second click within the SystemInformation.DoubleClickTime),Heer
M
6

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.

Monodrama answered 9/6, 2009 at 18:57 Comment(5)
Thanks for your answer! I haven't tried it because the first recommendation solved my problem - but thank you again! :)Cleave
I tried this and it works great. Hope this comment will be helpful for others. Thanks Josh.Prae
This will not impede the FIRST single click event, because for the first click event e.ClickCount = 1.Kimble
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#Ensoul
Isn't recommended to compute click before mouse up, because you prevent user to cancel the click.Valrievalry

© 2022 - 2024 — McMap. All rights reserved.