摘要:[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
}