tags:

views:

563

answers:

2

Consider the following code, I have a textblock that is an "on/off" button in WPF. It's just text inside an ellipse that says ON / OFF. When the user clicks the button and holds the left mouse for ONE second, it will execute the 'turn device on' code if the device is not already powered up. If the user holds the ON/OFF button for three seconds or more (keeps left mouse button HELD down) the device will turn off.

Several problems that I'm missing the boat on. 1. The tick event is not firing while the mouse button is held down, despite the fact the timer is started. 2. The do/while loop never exits despite lifting the button

Thanks!

    public int TimerCount = 0;

    private void ButtonPressTimer(object sender, EventArgs e)
    {
        TimerCount = TimerCount + 1;
    }

    private void txtBlockOnOff_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var buttonPressTimer = new DispatcherTimer(new TimeSpan(0, 0, 0, 1), DispatcherPriority.Normal, ButtonPressTimer, this.Dispatcher);

        do
        {
            if (!buttonPressTimer.IsEnabled)
                buttonPressTimer.Start();
        }
        while (e.ButtonState == MouseButtonState.Pressed);

        buttonPressTimer.Stop();
        if (TimerCount >= 3)
        {
            //do something here
        }
        else
        { 
            //do something different here
        }
    }
A: 

I'd look at a slightly different approach that doesn't require the overhead of setting up a timer. If you handle both the mouse down and up events, and store the time when the button was pressed, you can compare it to the time when the mouse is released and decide what to do.

private DateTime mousePressed;

private void txtBlockOnOff_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    mousePressed = DateTime.Now;
}

private void txtBlockOnOff_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    // button released

    TimeSpan difference = DateTime.Now - mousePressed;

    if (difference.TotalSeconds >= 3)
    {
        // long press
    }
    else
    {
        // short press
    }
}
Jason Anderson
By the way, your requirements say that a short press is 1 second, and a long press is 3 seconds, but this isn't what's reflected in the code. Like your original, my example assumes that a long press is anything over 3 seconds, and a short press is anything less. Changing this would be easy using the code I posted, since you can get as specific as you like when comparing against the TimeSpan.
Jason Anderson
+1  A: 

You're stuck in the loop - Dispatcher Timers fires on the same thread, but you're busy stuck in the Clicked handler.

Edit: Think about it - how is anyone going to change the MousePressed flag? There is only one thread (well technically, two, but remember it as one!) If you block in a handler, WPF can't do anything.

Paul Betts