c# 定時啟動一個操作、任務
- 2021 年 4 月 18 日
- 筆記
// 定時啟動一個操作、任務
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Timers; /* 功能:定時啟動一個操作。 作者:李茂平 用法: this.TimeWork = new TimeWork(); this.TimeWork.AddWork(new TimeWorkItem() { 任務名稱 = "任務一", Work = this.ClockMorningDownload, 計劃啟動時間 = "09:00", 任務說明 = "任務一說明 " }); this.TimeWork.SetEnable(true); */ namespace ClassLibrary { /// <summary> /// 定時執行任務的類,精度每分鐘 /// </summary> public class TimeWork : ObservableCollection<TimeWorkItem> { /// <summary> /// 使用多執行緒計時器 /// </summary> private readonly System.Timers.Timer timer1 = new System.Timers.Timer(); /// <summary> /// 運行的分鐘數 /// </summary> private int CountMin { get; set; } = 0; /// <summary> /// 當任務完成時 /// </summary> public Action<TimeWorkItem, TimeWorkLogItem> OnWorkFinished { get; set; } /// <summary> /// 執行記錄 /// </summary> public ObservableCollection<TimeWorkLogItem> LogItems { get; set; } = new ObservableCollection<TimeWorkLogItem>(); /// <summary> /// 構造函數,創建精度為1分鐘的定時器 /// </summary> public TimeWork() { this.timer1.Interval = 1 * 1000 * 60; // 1分鐘的定時器 this.timer1.Elapsed += timerMinute_Elapsed; this.timer1.Enabled = false; // 初始化為不發生定時事件 } /// <summary> /// 是否啟用定時任務 /// </summary> /// <param name="bEnable"></param> public void SetEnable(bool bEnable) { this.timer1.Enabled = bEnable; ResetRunTime(); } /// <summary> /// 定時器時間到,檢查啟動項目 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void timerMinute_Elapsed(object sender, ElapsedEventArgs e) { CountMin++; if (CountMin % 600 == 0) // 每10個小時重置一次 { ResetRunTime(); } DoTimerWork(); } /// <summary> /// 重新設定運行時間 /// </summary> public void ResetRunTime() { foreach (var item in this) { item.InitRunTimes(); } } /// <summary> /// 定時器時間到,檢查啟動項目 /// </summary> private void DoTimerWork() { DateTime now = DateTime.Now; foreach (var item in this) { foreach (var time in item.RunTimes) { if (time.Hours == now.Hour && time.Minutes == now.Minute) { Thread t = new Thread(() => { this.DoWork(item); }); t.Start(); } } } } /// <summary> /// 添加一個定時執行的項目 /// </summary> /// <param name="item"></param> public void AddWork(TimeWorkItem item) { this.Add(item); } /// <summary> /// 執行任務 /// </summary> /// <param name="item"></param> public void DoWork(TimeWorkItem item) { if (item != null && item.Work != null) { DateTime begin = DateTime.Now; item.Work(); // 執行工作 if (item.添加到執行記錄) LogItem(item, begin, DateTime.Now); item.上次執行時間 = begin.ToString("T"); } } /// <summary> /// 添加一條記錄到文件,記錄已經執行的任務 /// </summary> /// <param name="item"></param> private void LogItem(TimeWorkItem item, DateTime begin, DateTime end) { TimeWorkLogItem logItem = new TimeWorkLogItem(); logItem.任務名稱 = item.任務名稱; logItem.執行時間 = begin; logItem.完成時間 = end; this.LogItems.Add(logItem); if (OnWorkFinished != null) { OnWorkFinished(item, logItem); } //App.Data.UcDbModel.AddTimeWorksLog(logItem); } } /// <summary> /// MVVM模式下,更改屬性的通知 /// 首先定義NotificationObject類。目的是綁定數據屬性。 /// 這個類的作用是實現了INotifyPropertyChanged介面。 /// WPF中類要實現這個介面,其屬性成員才具備通知UI的能力 /// </summary> public class NotificationObjectEF : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } /// <summary> /// 定時工作項目 /// </summary> public class TimeWorkItem : NotificationObjectEF { public Action Work { get; set; } public string 任務名稱 { get; set; } public string 任務說明 { get; set; } /// <summary> /// 設定的計劃啟動日期,空格分開,如:每周6,每月1,空白意味著每天 /// 空白 -- 啟動 /// 周一 到 周日 啟動 /// 5月2日 啟動 /// </summary> public string 計劃啟動日期 { get; set; } /// <summary> /// 空格分開的多個時間:15:00 16:32 /// </summary> public string 計劃啟動時間 { get; set; } /// <summary> /// 間隔多少分鐘重複,每天執行 /// </summary> public int 間隔分鐘 { get; set; } /// <summary> /// 是否記錄到執行記錄 /// </summary> public bool 添加到執行記錄 { get; set; } = true; private string 上次執行時間_; public string 上次執行時間 { get { return 上次執行時間_; } set { 上次執行時間_ = value; RaisePropertyChanged("上次執行時間"); } } /// <summary> /// 運行任務的時間表 /// </summary> public ObservableCollection<TimeSpan> RunTimes { get; set; } = new ObservableCollection<TimeSpan>(); /// <summary> /// 運行任務的時間表 /// </summary> private string runTimeStr; /// <summary> /// 運行任務的時間表 /// </summary> public string RunTimesStr { get { return runTimeStr; } set { runTimeStr = value; RaisePropertyChanged("RunTimesStr"); } } /// <summary> /// 初始化時間 /// </summary> public void InitRunTimes() { // 分析時間 RunTimes.Clear(); if (!string.IsNullOrEmpty(計劃啟動時間) && IsTodayRun()) { string[] times = 計劃啟動時間.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); foreach (var item in times) { DateTime dt = new DateTime(); if (DateTime.TryParse(item, out dt)) { RunTimes.Add(dt.TimeOfDay); } } } if (間隔分鐘 > 0 && string.IsNullOrEmpty(計劃啟動日期) && string.IsNullOrEmpty(計劃啟動時間)) { DateTime now = DateTime.Now; DateTime oneTime = now.AddMinutes(間隔分鐘); DateTime EndTime = now.AddHours(12); while (oneTime <= EndTime) { RunTimes.Add(oneTime.TimeOfDay); oneTime = oneTime.AddMinutes(間隔分鐘); } } // 設置字元串 string newRunTimesStr = ""; foreach (TimeSpan ts in RunTimes) { newRunTimesStr += $"{ts.Hours:00}:{ts.Minutes:00} "; } RunTimesStr = newRunTimesStr; } /// <summary> /// 判斷今日是否是執行日期. /// 空白 -- 是 /// 周一 到周日 是 /// 5月2日 是 /// </summary> /// <returns></returns> private bool IsTodayRun() { if (string.IsNullOrEmpty(this.計劃啟動日期)) return true; string[] days = 計劃啟動日期.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); foreach (var item in days) { if (item.Contains("周") || item.Contains("星期")) { if (DateTime.Now.DayOfWeek == ConvertToDayOfWeek(item)) return true; } if (item.Contains("月") || item.Contains("日")) { string full = $"{DateTime.Now.Year}年" + item; if(DateTime.TryParse(full, out DateTime setDate)) { if (setDate.Date == DateTime.Now.Date) return true; } } } return false; } private DayOfWeek ConvertToDayOfWeek(string item) { switch(item) { case "周一": case "星期一": return DayOfWeek.Monday; case "周二": case "星期二": return DayOfWeek.Tuesday; case "周三": case "星期三": return DayOfWeek.Wednesday; case "周四": case "星期四": return DayOfWeek.Thursday; case "周五": case "星期五": return DayOfWeek.Monday; case "周六": case "星期六": return DayOfWeek.Saturday; case "周日": case "星期日": return DayOfWeek.Sunday; default: return DayOfWeek.Sunday; } } } [Serializable] public class TimeWorkLogItem { /// <summary> /// 名稱 /// </summary> public string 任務名稱 { get; set; } /// <summary> /// 上次執行時間 /// </summary> public DateTime 執行時間 { get; set; } /// <summary> /// 完成時間 /// </summary> public DateTime 完成時間 { get; set; } } }