1

I created a timer with C#. I can schedule any operation in seconds, minutes or daily. However, there is a situation where I want to stop this timer, then change its parameters and run it again (ex. when the button is clicked). How can I do it?

Below are the codes I wrote.

SchedulerService.cs

public class SchedulerService
{
    private static SchedulerService _instance;
    private List<Timer> timers = new List<Timer>();
    private SchedulerService() { }
    public static SchedulerService Instance => _instance ?? (_instance = new SchedulerService());
    public void ScheduleTask(int hour, int min, double intervalInHour, Action task)
    {
        DateTime now = DateTime.Now;
        DateTime firstRun = new DateTime(now.Year, now.Month, now.Day, hour, min, 0, 0);
        if (now > firstRun)
        {
            firstRun = firstRun.AddDays(1);
        }
        TimeSpan timeToGo = firstRun - now;
        if (timeToGo <= TimeSpan.Zero)
        {
            timeToGo = TimeSpan.Zero;
        }
        var timer = new Timer(x =>
        {
            task.Invoke();
        }, null, timeToGo, TimeSpan.FromHours(intervalInHour));
        timers.Add(timer);
    }
}

Scheduler.cs(File inside your root directory)

public class Scheduler
    {
        public static void IntervalInSeconds(int hour, int sec, double interval, Action task)
        {
            interval = interval / 3600;
            SchedulerService.Instance.ScheduleTask(hour, sec, interval, task);
        }
        public static void IntervalInMinutes(int hour, int min, double interval, Action task)
        {
            interval = interval / 60;
            SchedulerService.Instance.ScheduleTask(hour, min, interval, task);
        }
        public static void IntervalInHours(int hour, int min, double interval, Action task)
        {
            SchedulerService.Instance.ScheduleTask(hour, min, interval, task);
        }
        public static void IntervalInDays(int hour, int min, double interval, Action task)
        {
            interval = interval * 24;
            SchedulerService.Instance.ScheduleTask(hour, min, interval, task);
        }

    }

Form1.cs

Scheduler.IntervalInMinutes(hour,minute,interval,
() =>
{
 MyFunc();
});
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
ahta14
  • 115
  • 3
  • 9

1 Answers1

1

I wouldn't re-invent the wheel. Microsoft already has a library that does this nicely for you. You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq;.

You can do this kind of thing:

IDisposable subscription =
    Observable
        .Interval(TimeSpan.FromSeconds(1.0))
        .Subscribe(x => Console.WriteLine(x));

This will fire an event every second. If you want to stop it just call subscription.Dispose();

If you want a different period then pass in something like TimeSpan.FromDays(2.0).

Now, if you want to be able to change the period you can do this:

Subject<TimeSpan> subject = new Subject<TimeSpan>();

IObservable<long> interval =
    subject
        .Select(timespan => Observable.Interval(timespan))
        .Switch();

IDisposable subscription =
    interval
        .Subscribe(x => Console.WriteLine(x));

Now, to start the interval going I would call this:

subject.OnNext(TimeSpan.FromSeconds(1.0));

If I now want to change it I just do this:

subject.OnNext(TimeSpan.FromHours(2.0));

And, again, to stop it just call subscription.Dispose();.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172