views:

130

answers:

7

I want to create a background worker for a WinForm that triggers code whenever midnight rolls by.

I have an idea of how to do it, but I'm pretty sure it's not the best way to do it.

while(1==1)
{
//if Datetime.Now == midnight, execute code
//sleep(1second)
}
+6  A: 

Instead you could user a Timer and set the timer tick interval to be the time between Now() and midnight.

AaronLS
A: 

you can use Quartz to schedule that. Maybe is like a cannon to kill a mosquito in this scenario, but that's is the only scheduling job framework i know and works excellent.

Markust
+9  A: 

Use a System.Timers.Timer and at application start up just calculate the difference between DateTime.Now and DateTime.Today.AddDays(0). Then set the interval for that amount.

I actually did something just like this recently:

public static class DayChangedNotifier
{
    private static Timer timer;

    static DayChangedNotifier()
    {
        timer = new Timer(GetSleepTime());
        timer.Elapsed += (o, e) =>
            {
                OnDayChanged(DateTime.Now.DayOfWeek);
                timer.Interval = this.GetSleepTime();
            };
        timer.Start();

        SystemEvents.TimeChanged += new EventHandler(SystemEvents_TimeChanged);
    }

    private static void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        timer.Interval = GetSleepTime();
    }

    private static double GetSleepTime()
    {
        var midnightTonight = DateTime.Today.AddDays(1);
        var differenceInMilliseconds = (midnightTonight - DateTime.Now).TotalMilliseconds;
        return differenceInMilliseconds;
    }

    private static void OnDayChanged(DayOfWeek day)
    {
        var handler = DayChanged;
        if (handler != null)
        {
            handler(null, new DayChangedEventArgs(day));
        }
    }

    public static event EventHandler<DayChangedEventArgs> DayChanged;
}

AND:

public class DayChangedEventArgs : EventArgs
{
    public DayChangedEventArgs(DayOfWeek day)
    {
        this.DayOfWeek = day;
    }

    public DayOfWeek DayOfWeek { get; private set; }
}

Useage: DayChangedNotified.DayChanged += ....

BFree
So I wouldn't even need a background worker?
Soo
@Soo: Nope. The Timer won't block (stopping the rest of your code -- http://en.wikipedia.org/wiki/Blocking_%28computing%29). Once the interval is up, it will call the `Tick` event. At that point you can stop the timer if you wish, calculate the next interval and start it up again.
Nelson
No, the System.Timers fires on another thread so all you need to be careful about is to call Invoke in your event handler of the timer.
BFree
You stole my answer! LOL j/k +1 for giving him a great example.
AaronLS
@BFree: Or use a System.Windows.Forms.Timer instead, this one fires the Tick() event in the Form's thread.
SchlaWiener
A: 

Don't use polling. Instead, set up a timer task, set it to fire at midnight, and add an event to process.

 TimeSpan timeBetween = DateTime.Today.AddDays(1) - DateTime.Now;

 System.Timers.Timer t = new System.Timers.Timer();
 t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
 t.Interval = 1000 * timeBetween.Seconds;
 t.Start();
MrGumbe
So after t_Elapsed is triggered, is timeBetween recalculated?
Soo
You would recalculate the interval in the t_Elapsed method.
MrGumbe
A: 

Quartz is a very good idea. I don't think this is a cannon to kill a mosquito, I think this is a very flexible solution :)

jaspion
A: 

I have no idea why polling solutions were voted up when Microsoft solved this type of problem years ago by adding a windows service to handle timing. Just create a scheduled task to run the exe. No extra overhead.

P.Brian.Mackey
A: 

I'm a little confuse about why you need a WinForm, will it be running at midnight? If all you need is some sort process to run, use the windows scheduler to run it at midnight. (On XP, but I believe Win server should be similar)Control Panel -> Scheduled Tasks -> Add Scheduled Task -> Fill out the wizard. Save you a lot of coding.

Chris L