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; }
}
}