目录
1.System.Timers.Timer
2.System.Windows.Forms.Timer
3.System.Threading.Timer
4.简单的封装
这里介绍三种常用的定时器,方便查阅资料或直接复制使用。
1.System.Timers.Timer
System.Timers.Timer
类定义了一个计时器,该计时器按固定间隔触发事件。它主要用于多线程环境,特别是在基于服务器的组件或服务组件中。此类没有用户界面,在运行时不可见,特别适用于后台任务处理。
主要属性和方法
- Interval:以毫秒为单位,设置或获取引发
Elapsed
事件的时间间隔。 - AutoReset:设置或获取一个值,该值指示计时器在
Elapsed
事件触发后是否自动重置,并继续计时(true
)或停止计时(false
)。 - Enabled:设置或获取一个值,该值指示计时器是否已启用(
true
)或已禁用(false
)。 - Start():通过将
Enabled
设置为true
来启动计时器。 - Stop():通过将
Enabled
设置为false
来停止计时器。 - Elapsed 事件:当指定的时间间隔过去时,将触发此事件。该事件处理函数在新的线程中执行,因此不能直接访问UI控件(需通过委托和Invoke方法)。
使用场景
适用于需要按固定时间间隔执行任务的后台服务或应用程序,如定期检查数据库、更新状态信息等。
用法:
namespace Test2
{internal class Program{private static System.Timers.Timer Timer;static void Main(string[] args){Timer = new System.Timers.Timer();Timer.Interval = 2000; //间隔时间2000毫秒Timer.AutoReset = true;//是否重复执行Timer.Elapsed += Timer_Elapsed;Timer.Enabled = true; //或者使用 Timer.Start() 效果一样Console.ReadKey();}private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e){Console.WriteLine("需要重复执行的代码");}}
}
2.System.Windows.Forms.Timer
System.Windows.Forms.Timer
控件是Windows窗体环境中的定期事件引发组件。它主要用于单线程环境,特别是在UI更新中。该计时器是同步的,意味着它在UI线程上执行,不会阻塞或干扰UI操作。
主要属性和方法
- Interval:以毫秒为单位,设置或获取计时器事件之间的时间间隔。
- Enabled:设置或获取一个值,该值指示计时器是否已启用(
true
)或已禁用(false
)。 - Start():启动计时器。
- Stop():停止计时器。
- Tick 事件:当指定的时间间隔过去时,将触发此事件。与
System.Timers.Timer
不同,Tick
事件在UI线程上执行,因此可以直接访问UI控件。
使用场景
适用于需要按固定时间间隔更新UI元素的场景,如时钟、动画、进度条更新等。
System.Windows.Forms.Timer 可以在 Winform 工具箱中直接拖入到 Winform 界面中,也可以直接在代码中添加,System.Windows.Forms.Timer 在定时器回调中可以调用 Winform 的界面控件,而 System.Timers.Timer 回调内使用 Winform 控件会存在跨线程的错误。
用法同 System.Timers.Timer 差不多,用工具箱中的 Timer 可以少写很多代码。
代码:
using System;
using System.Windows.Forms;namespace Test1
{public partial class Form1 : Form{public Form1(){InitializeComponent();}System.Windows.Forms.Timer Timer;private void Form1_Load(object sender, EventArgs e){Timer = new System.Windows.Forms.Timer();Timer.Interval = 1000;Timer.Tick += Timer_Tick;Timer.Start();}private void Timer_Tick(object sender, EventArgs e){Console.WriteLine("需要重复执行的代码");}}
}
3.System.Threading.Timer
System.Threading.Timer
类由线程池调用,专门用于在线程池线程上按固定间隔执行单个回调方法。它是为服务器或后台应用程序设计的,可以优化系统资源的使用。
主要属性和方法
- Callback:定义在指定时间间隔后调用的回调方法。
- State:传递给回调方法的对象,作为回调方法的参数。
- DueTime:计时器第一次触发之前延迟的时间(以毫秒为单位)。
- Period:计时器每次触发之间的时间间隔(以毫秒为单位)。设置为
Timeout.Infinite
表示计时器只触发一次。 - Change(Int64, Int64):在计时器启动后更改其
DueTime
和Period
设置。 - Dispose():释放
Timer
对象使用的资源。
使用场景
适用于需要定期执行长时间运行或资源密集型任务的后台应用程序,如文件清理、数据同步等。由于回调方法在线程池线程上执行,因此不会影响UI线程的性能。
代码:
namespace Test2
{internal class Program{private static System.Threading.Timer Timer;static void Main(string[] args){//参数1 要定时执行的回调//参数2 定时回调的参数//参数3 延迟多少秒开始执行//参数4 定时器的间隔时间Timer = new System.Threading.Timer(OnTimedEvent, null, 0, 1000);Console.ReadKey();}private static void OnTimedEvent(Object state){Console.WriteLine("需要重复执行的代码");}}
}
可以使用下面的方法来停止定时器
// 暂时停止定时器
Timer.Change(Timeout.Infinite, Timeout.Infinite);
如果需要继续执行定时器,可以使用下面的方法
// 重新启动定时器:初始延迟1000毫秒,每2000毫秒触发一次
Timer.Change(1000, 2000);
其实还有一个定时器 System.Web.UI.Timer,只是现在用的人比较少,这里就不做介绍了。
4.简单的封装
根据上面的代码可以发现,就那几行代码,复制来复制去的有点麻烦,我这里稍微封装一下,一句代码搞定定时器,非常的方便。
新建一个类 TimerScheduler
using System;
using System.Collections.Generic;
using System.Threading.Tasks;/// <summary>
/// 定时器的封装
/// </summary>
public class TimerScheduler
{private static Dictionary<string, ActionSchedulerInfo> SchedulerDic = new Dictionary<string, ActionSchedulerInfo>();/// <summary>/// 添加定时执行委托/// </summary>/// <param name="key">唯一的Key</param>/// <param name="intervalInSeconds">定时器间隔时间</param>/// <param name="isUIThread">是否是UI线程</param>/// <param name="action">定时器回调</param>public static void Add(string key, double intervalInSeconds, bool isUIThread, Action action){if (action == null){Console.WriteLine("参数 action 不能为空");return;}if (string.IsNullOrEmpty(key)){Console.WriteLine("参数 key 不能为空");return;}if (SchedulerDic.ContainsKey(key)){Console.WriteLine($"{key} 不能重复的添加");return;}if (intervalInSeconds <= 0 || intervalInSeconds > 86400){Console.WriteLine($"{key} 的间隔时间超过了指定的范围");return;}var actionScheduler = new ActionSchedulerInfo();if (isUIThread){actionScheduler.timerUI = new System.Windows.Forms.Timer();actionScheduler.timerUI.Interval = (int)TimeSpan.FromSeconds(intervalInSeconds).TotalMilliseconds;actionScheduler.timerUI.Tick += (sender, e) => action();actionScheduler.timerUI.Start();}else{actionScheduler.timer = new System.Timers.Timer();actionScheduler.timer.Interval = TimeSpan.FromSeconds(intervalInSeconds).TotalMilliseconds;actionScheduler.timer.Elapsed += (sender, e) => Task.Run(action);actionScheduler.timer.AutoReset = true;actionScheduler.timer.Start();}SchedulerDic[key] = actionScheduler;}/// <summary>/// 移除定时执行委托/// </summary>/// <param name="key"></param>public static void Remove(string key){if (SchedulerDic.TryGetValue(key, out var scheduler)){if (scheduler.timer != null){scheduler.timer.Stop();scheduler.timer.Dispose();}if (scheduler.timerUI != null){scheduler.timerUI.Stop();scheduler.timerUI.Dispose();}scheduler.actions = null;SchedulerDic.Remove(key);}}/// <summary>/// 移除所有的定时器/// </summary>public static void Dispose(){foreach (var scheduler in SchedulerDic.Values){if (scheduler.timer != null){scheduler.timer.Stop();scheduler.timer.Dispose();scheduler.actions = null;}if (scheduler.timerUI != null){scheduler.timerUI.Stop();scheduler.timerUI.Dispose();scheduler.actions = null;}}SchedulerDic.Clear();}public class ActionSchedulerInfo{public System.Timers.Timer timer { get; set; }public System.Windows.Forms.Timer timerUI { get; set; }public Action actions { get; set; }}
}
添加:
TimerScheduler.Add("Test", 2, false, () =>
{Console.WriteLine("这是一个定时器");
});
这里使用了一个 Lambda 表达式,你可以直接替换成一个无参数的方法。
移除:
TimerScheduler.Remove("Test");
移除对应的 key,就能停止和清除这个定时器了。
end