Alterecho
Alterecho

Reputation: 715

Timer methods not called

I have setup a timer:

System.Timers.Timer timer = new System.Timers.Timer (1000);
timer.Enabled = true;
timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
            timer.Enabled = false;
            ui.CldOnPhoneNumberSent(); // <- this method is not fired
        };

the second method is not called. if i switch the methods as in:

timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
    ui.CldOnPhoneNumberSent(); 
    timer.Enabled = false; // <- this method is not called and the timer repeats
}

what's wrong?

Edit: When the method is called from a timer, it's not called completely!:

timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
                ((Timer)sender).Enabled = false;
                ui.method1();
};

void method1()
{
   do something; //<-- called
   do Something; //<-- not called 
}

Upvotes: 1

Views: 119

Answers (2)

Kryptos
Kryptos

Reputation: 875

As was said in comments, the most likely reason is that your CldOnPhoneNumberSent() throws some exception preventing further execution.

You should rewrite as follow:

var timer = new System.Timers.Timer (1000);
timer.Elapsed += (sender, args) =>
{
    ((Timer)sender).Enabled = false;
    try
    {
        ui.CldOnPhoneNumberSent();
    }
    catch (Exception e)
    {
        // log exception
        // do something with it, eventually rethrow it
    }
};
timer.Enabled = true;

Note that is you are inside a WPF application and want to access object created in the UI thread, you may need to dispatch the call:

Action callback = ui.CldOnPhoneNumberSent;
var app = Application.Current;
if (app == null)
{
    // This prevents unexpected exceptions being thrown during shutdown (or domain unloading).
    return;
}
if (app.CheckAccess())
{
    // Already on the correct thread, just execute the action
    callback();
}
else
{
    // Invoke through the dispatcher
    app.Dispatcher.Invoke(callback);
}

As a final note, if you are using .Net 4.5 (with C# 5) you might consider using the async/await pattern instead of System.Timers.Timer, which is easier to use and more readable:

private async Task YourMethod()
{
    await Task.Delay(1000)
        .ConfigureAwait(continueOnCapturedContext: true); // this makes sure continuation is on the same thread (in your case it should be the UI thread)
    try
    {
        ui.CldOnPhoneNumberSent();
    }
    catch (Exception e)
    {
        // log exception
        // do something with it, eventually rethrow it
    }
}

Upvotes: 0

D Stanley
D Stanley

Reputation: 152654

It could be a problem with variable closure in the anonymous method - try using the sender value instead of referencing timer:

timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
        ((Timer)sender).Enabled = false;
        ui.CldOnPhoneNumberSent(); // <- this method is not fired
    };

Upvotes: 1

Related Questions