[c#]自製排程器

  • 17727
  • 0
  • C#
  • 2017-08-21

摘要:[c#]自製排程器

前陣子參考BillChung的自製簡易排程器(2)一文,在獲得BillChung的同意之後,將其改成C#版本 並放置於點部落。

由於C#沒有提供DateDiff函數, 因此我在Scheduler.cs 中增加了一個DateDiff函數 以及 一個DateInterval列舉,

當然,也可以使用Microsoft.VisualBasic.DateAndTime.DateDiff函數 (必須將Microsoft.VisualBasic.dll加入參考)。

完整的程式 

Form1.cs

    public partial class Form1 : Form
    {
        #region delegate
        delegate void SetMsg1Callback(string InputString);
        delegate void SetMsg2Callback(string InputString);
        #endregion

        Scheduler myScheduler;
        
        public Form1()
        {
            InitializeComponent();
        }
        
        private void DisplayMsg1(string strReceive)
        {
            try
            {
                if (this.Label10.InvokeRequired)
                {
                    SetMsg2Callback d = new SetMsg2Callback(DisplayMsg1);
                    this.Invoke(d, strReceive);
                }
                else
                {
                    this.Label10.Text = strReceive;
                }
            }
            catch (ObjectDisposedException ex)
            {
                //停止的時候有可能會造成 ObjectDisposedException
                //請參閱 [Try Catch能幫你做什麼(4)?] http://www.dotblogs.com.tw/billchung/archive/2009/04/04/7851.aspx
            }
        }

        private void DisplayMsg2(string strReceive)
        {
            try
            {
                if (this.Label2.InvokeRequired)
                {
                    SetMsg2Callback d = new SetMsg2Callback(DisplayMsg2);
                    this.Invoke(d, strReceive);
                }
                else
                {
                    this.Label2.Text = strReceive;
                }
            }
            catch (ObjectDisposedException ex)
            {
                //停止的時候有可能會造成 ObjectDisposedException
                //請參閱 [Try Catch能幫你做什麼(4)?] http://www.dotblogs.com.tw/billchung/archive/2009/04/04/7851.aspx
            }
        }

        private void test(object state)
        {
            DisplayMsg2("End:" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff"));
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.SelectedIndex = 0;

            for (int i = 0; i < 7; i++)
                comboBox2.Items.Add(Enum.GetName(typeof(DayOfWeek), i));
            comboBox2.SelectedIndex = 0;
            myScheduler  = new Scheduler(test);

        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (comboBox1.SelectedIndex)
            {
                case 0:
                    comboBox2.Enabled = false;
                    NUD_Date.Enabled = false;
                    break;
                case 1:
                    comboBox2.Enabled = false;
                    NUD_Date.Enabled = false;
                    break;
                case 2:
                    comboBox2.Enabled = true;
                    NUD_Date.Enabled = false;
                    break;
                case 3:
                    comboBox2.Enabled = false;
                    NUD_Date.Enabled = true;
                    break;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            myScheduler.DoPeriod = (Scheduler.Period)comboBox1.SelectedIndex;
            myScheduler.WorkTime = new Scheduler.RunningTime(Convert.ToInt32(NUD_Hour.Value), Convert.ToInt32(NUD_Minute.Value), Convert.ToInt32(NUD_Second.Value));
            myScheduler.MonthDay = Convert.ToInt32(NUD_Date.Value);
            myScheduler.WeekDay = (System.DayOfWeek)comboBox2.SelectedIndex;
            myScheduler.SchTimerStart();
            Label1.Text = "Begin:" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            myScheduler.DoPeriod = (Scheduler.Period)comboBox1.SelectedIndex;
            myScheduler.WorkTime = new Scheduler.RunningTime(Convert.ToInt32(NUD_Hour.Value), Convert.ToInt32(NUD_Minute.Value), Convert.ToInt32(NUD_Second.Value));
            myScheduler.MonthDay = Convert.ToInt32(NUD_Date.Value);
            myScheduler.WeekDay = (System.DayOfWeek)comboBox2.SelectedIndex;
            Label1.Text = "Begin:" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Label10.Text = "NextTime:" + myScheduler.NextTime;
        }

    }


 

Scheduler.cs

    public class Scheduler
    {
        #region Enum
        public enum Period
        {
            Hourly,
            Daily,
            Weekly,
            Monthly
        }

        enum DateInterval
        {
            Second,
            Minute,
            Hour,
            Day,
            Month,
            Year
        }
        #endregion

        #region RunningTime Class
        public class RunningTime
        {
            private int _hour, _minute, _second;
            public int Hour
            {
                get
                {
                    return _hour;
                }
                set
                {
                    if (value < 0 || value > 23)
                        _hour = 0;
                    else
                        _hour = value;
                }
            }

            public int Minute
            {
                get
                {
                    return _minute;
                }
                set
                {
                    if (value < 0 || value > 59)
                        _minute = 0;
                    else
                        _minute = value;
                }
            }

            public int Second
            {
                get
                {
                    return _second;
                }
                set
                {
                    if (value < 0 || value > 59)
                        _second = 0;
                    else
                        _second = value;
                }
            }

            public RunningTime()
            {
                _hour = 0;
                _minute = 0;
                _second = 0;
            }
            public RunningTime(int hour, int minute, int second)
            {
                _hour = hour;
                _minute = minute;
                _second = second;
            }

        }
        #endregion


        private Period _Period;
        private RunningTime _WorkTime;
        private DateTime _NextTime;
        private bool _IsStart;
        private DayOfWeek _WeekDay;
        private int _MonthDay;
        private System.Threading.Timer SchTimer;

        #region property
        public Period DoPeriod
        {
            get
            {
                return _Period;
            }
            set
            {
                _Period = value;
                TimeChanged();
            }
        }

        public RunningTime WorkTime
        {
            get
            {
                return _WorkTime;
            }
            set
            {
                _WorkTime = value;
                TimeChanged();
            }
        }

        public DateTime NextTime
        {
            get
            {
                return _NextTime;
            }
            set
            {
                _NextTime = value;
            }
        }

        public bool IsStart
        {
            get
            {
                return _IsStart;
            }
            set
            {
                _IsStart = value;
            }
        }

        public DayOfWeek WeekDay
        {
            get
            {
                return _WeekDay;
            }
            set
            {
                _WeekDay = value;
            }

        }

        public int MonthDay
        {
            get
            {
                return _MonthDay;
            }
            set
            {
                _MonthDay = value;
            }
        }
        #endregion

        public delegate void SchCallBack(object state);


        #region Constructor

        public Scheduler(SchCallBack TCallBack)
        {
            _Period = Period.Daily;
            _WorkTime = new RunningTime(0, 0, 0);
            _IsStart = false;
            Microsoft.Win32.SystemEvents.TimeChanged += new EventHandler(SysTimeChanged);
            object objstate = TCallBack;
            SchTimer = new System.Threading.Timer(myCallBack, objstate, -1, 0);
        }
        #endregion

        #region public method
        public void SchTimerStart()
        {
            _IsStart = true;
            TimeChanged();
        }
        #endregion

        #region private method
        private void SysTimeChanged(object sender, EventArgs e)
        {
            //當系統時間被改變,呼叫Timechanged
            TimeChanged();
        }

        private void myCallBack(Object state)
        {
            (state as SchCallBack).Invoke(null);
            TimeChanged();
        }

        private void TimeChanged()
        {
            if (_IsStart)
                SchTimer.Change(CalcNext(), 0);
        }

        private long CalcNext()
        {
            DateTime dTimeNow, dNextTime;
            dTimeNow = DateTime.Now;

            switch (_Period)
            {
                case Period.Hourly:
                    if (CalTotalSeconds(0, 0, dTimeNow.Minute, dTimeNow.Second) >= CalTotalSeconds(0, 0, _WorkTime.Minute, _WorkTime.Second))
                        dNextTime = Convert.ToDateTime(dTimeNow.AddHours(1).ToString("yyyy/MM/dd HH") + ":" + _WorkTime.Minute + ":" + _WorkTime.Second);
                    else
                        dNextTime = Convert.ToDateTime(dTimeNow.ToString("yyyy/MM/dd HH") + ":" + _WorkTime.Minute + ":" + _WorkTime.Second);
                    break;
                case Period.Daily:
                    if (CalTotalSeconds(0, dTimeNow.Hour, dTimeNow.Minute, dTimeNow.Second) >= CalTotalSeconds(0, _WorkTime.Hour, _WorkTime.Minute, _WorkTime.Second))
                        dNextTime = Convert.ToDateTime(dTimeNow.AddDays(1).ToString("yyyy/MM/dd") + " " + _WorkTime.Hour + ":" + _WorkTime.Minute + ":" + _WorkTime.Second);
                    else
                        dNextTime = Convert.ToDateTime(dTimeNow.ToString("yyyy/MM/dd") + " " + _WorkTime.Hour + ":" + _WorkTime.Minute + ":" + _WorkTime.Second);
                    break;
                case Period.Weekly:
                    if (CalTotalSeconds((int) dTimeNow.DayOfWeek, dTimeNow.Hour, dTimeNow.Minute, dTimeNow.Second) >= CalTotalSeconds((int)_WeekDay, _WorkTime.Hour, _WorkTime.Minute, _WorkTime.Second))
                        dNextTime = Convert.ToDateTime(dTimeNow.AddDays((int)_WeekDay - (int)dTimeNow.DayOfWeek + 7).ToString("yyyy/MM/dd") + " " + _WorkTime.Hour + ":" + _WorkTime.Minute + ":" + _WorkTime.Second);
                    else
                        dNextTime = Convert.ToDateTime(dTimeNow.AddDays((int)_WeekDay - (int) dTimeNow.DayOfWeek).ToString("yyyy/MM/dd") + " " + _WorkTime.Hour + ":" + _WorkTime.Minute + ":" + _WorkTime.Second);
                    break;
                default:
                    DateTime dChkTime;
                    dChkTime = Convert.ToDateTime(dTimeNow.ToString("yyyy/MM") + "/01 00:00:00");
                    if (CalTotalSeconds(dTimeNow.Day - 1, dTimeNow.Hour, dTimeNow.Minute, dTimeNow.Second) >= CalTotalSeconds(_MonthDay - 1, _WorkTime.Hour, _WorkTime.Minute, _WorkTime.Second))
                        dNextTime = FindNextDayofMonth(dChkTime.AddMonths(1));
                    else
                        dNextTime = FindNextDayofMonth(dChkTime);
                    break;

            }
            _NextTime = dNextTime;
            return CalcToMS(dTimeNow, dNextTime);
        }


        private DateTime FindNextDayofMonth(DateTime dChkTime)
        {
            if (DateTime.DaysInMonth(dChkTime.Year, dChkTime.Month) >= _MonthDay)
                return Convert.ToDateTime(dChkTime.ToString("yyyy/MM") + "/" + Convert.ToString(_MonthDay).Trim() + " " + _WorkTime.Hour + ":" + _WorkTime.Minute + ":" + _WorkTime.Second);
            else
                dChkTime = dChkTime.AddMonths(1);
            return FindNextDayofMonth(dChkTime);
        }

        private int CalTotalSeconds(int Day, int Hour, int Minute, int Second)
        {
            return Day * 86400 + Hour * 3600 + Minute * 60 + Second;
        }

        private long CalcToMS(DateTime dTimeNow, DateTime dNextTime)
        {

            long lNextTime = 0;
            lNextTime = DateDiff(DateInterval.Second, dTimeNow, dNextTime) + 1;
            return lNextTime * 1000;
        }

        private int DateDiff(DateInterval interval, DateTime FirstDateTime, DateTime SecondDateTime)
        {
            TimeSpan span;
            if (FirstDateTime > SecondDateTime)
                span = FirstDateTime - SecondDateTime;
            else
                span = SecondDateTime - FirstDateTime;

            switch (interval)
            {
                case DateInterval.Year:
                    if (FirstDateTime.Year > SecondDateTime.Year)
                        return FirstDateTime.Year - SecondDateTime.Year;
                    else
                        return SecondDateTime.Year - FirstDateTime.Year;
                case DateInterval.Month:
                    if ((FirstDateTime.Year * 12 + FirstDateTime.Month) > (SecondDateTime.Year * 12 + SecondDateTime.Month))
                        return (FirstDateTime.Year * 12 + FirstDateTime.Month) - (SecondDateTime.Year * 12 + SecondDateTime.Month);
                    else
                        return (SecondDateTime.Year * 12 + SecondDateTime.Month) - (FirstDateTime.Year * 12 + FirstDateTime.Month);
                case DateInterval.Day:
                    return span.Days;
                case DateInterval.Hour:
                    return span.Days * 24 + span.Hours;
                case DateInterval.Minute:
                    return span.Days * 1440 + span.Hours * 60 + span.Minutes;
                case DateInterval.Second:
                    return span.Days * 86400 + span.Hours * 3600 + span.Minutes * 60 + span.Seconds;
                default:
                    return -1;
            }
        }

        #endregion
    }

CSharpScheduler.rar