mmr
mmr

Reputation: 14919

Why is this C# timer code not working?

I need to be able to disable a button for 1.5 seconds at a time for an application I'm writing. An image is displayed, a user clicks a button, and then another image is displayed. I need to make sure that the user doesn't click the button again too quickly.

So, when the image is displayed, I call this function:

    //when a new image is displayed, start the timer and disable the 'done' button
    //for 1.5 seconds, to force people to stop pressing next so quickly
    System.Timers.Timer mTimer;
    void TimerStart() {
        Done.IsEnabled = false;

        mTimer = new System.Timers.Timer();
        mTimer.Interval = 1500;
        mTimer.Start();
        mTimer.Elapsed += new System.Timers.ElapsedEventHandler(TimerEnd);
    }

The TimerEnd code looks like:

    void TimerEnd(object sender, EventArgs eArgs) {
        if (sender == mTimer){
            Done.IsEnabled = true;
            mTimer.Stop();
        }
    }

The 'Done.IsEnabled' line gets hit, but the button is not reenabled and the timer doesn't stop firing. What am I doing wrong here? If it matters, this is a WPF app.

Upvotes: 3

Views: 10440

Answers (4)

Abhijeet Patel
Abhijeet Patel

Reputation: 6878

When working with WPF there is no guarantee that updates made to UI controls on non-UI threads will work as expected. In many cases you will get an exception when you do this.

In your Timer elapsed handler you need to use the BeginInvoke/EndInvoke paradigm and put your button enabling logic in there to ensure that this code runs on the UI thread instead of Begin/End Invoke

There is a SynchnornizationContext available as well which can be accessed by calling SynchronizationContext.Current . You'll need to cache this before you make the timer call since SynchronizationContext.Current will be null in non-UI threads.

This link talks about this as well.

Upvotes: 0

whatnick
whatnick

Reputation: 5470

Basically you are trying to debounce the button, to prevent too quick clicks. Rather than use a timer save the previous click time in millis, if the button is clicked again within a short time ignore the next event.

Upvotes: 2

Sorantis
Sorantis

Reputation: 14722

Use DispatcherTimer instead

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(someInterval);
timer.Tick += new EventHandler(someEventHandler);
timer.Start();

private void someEventHandler(Object sender, EventArgs args)
{
//some operations
//if you want this event handler executed for just once
// DispatcherTimer thisTimer = (DispatcherTimer)sender;
// thisTimer.Stop();
}

Upvotes: 7

Joel Coehoorn
Joel Coehoorn

Reputation: 415735

The timer event is raised on a different thread. When working with the winforms controls, you need to make sure you Invoke them from the same thread where they were called.

Upvotes: 1

Related Questions