如何实现每两分钟执行一次操作的Timer定时器?
问题:Timer每两分钟执行一次操作,仅首次触发后续失效
我希望Timer每两分钟执行一次操作,使用Stopwatch和Timer组件实现,但目前仅在第一个两分钟后执行操作,后续周期均失效。以下是我尝试的两种代码逻辑及完整实现代码,寻求正确的改写方案:
尝试的两种逻辑
第一种逻辑
MainTimer.Text = stopwatch.Elapsed.ToString(@"hh\:mm\:ss"); double counter = stopwatch.Elapsed.TotalSeconds; if ((int)counter == 120 ) { // do sth counter = 0; }
第二种逻辑
MainTimer.Text = stopwatch.Elapsed.ToString(@"hh\:mm\:ss"); double counter = stopwatch.Elapsed.TotalSeconds; if ((int)counter % 120 == 0 ) { // do sth }
完整实现代码
Timer timer = new Timer(1000); Stopwatch stopwatch = new Stopwatch(); public MainPage() { InitializeComponent(); MainFunctionTimer(); DeviceDisplay.KeepScreenOn = true; } bool Value = false; string Time = "00:00:00"; private void MainFunctionTimer() { MainTimer.Text = Time; stopwatch = new Stopwatch(); timer.Interval = 500; timer.Elapsed += OnTimerElapsed; } private void OnTimerElapsed(object sender, ElapsedEventArgs e) { Application.Current.Dispatcher.BeginInvokeOnMainThread(() => { MainTimer.Text = stopwatch.Elapsed.ToString(@"hh\:mm\:ss"); double counter = stopwatch.Elapsed.TotalSeconds; if ((int)counter == 120 ) { // do sth counter = 0; } }); } private void Start_Stop_Butt_Clicked(object sender, EventArgs e) { if (Value == false) { Value = true; stopwatch.Start(); timer.Start(); } else { Value = false; stopwatch.Stop(); timer.Stop(); } } private void Reset_Clicked(object sender, EventArgs e) { stopwatch.Reset(); MainTimer.Text = Time; }
问题分析与解决方案
问题原因
- 第一种逻辑中,你重置的是局部变量
counter,而非Stopwatch的计时,Stopwatch会继续累计时间,后续counter永远不会再等于120。 - 第二种逻辑会在0、120、240等秒数触发,但因为Timer的Interval是500ms,在120秒的瞬间会连续触发多次(比如TotalSeconds在120.0到120.5之间时,(int)counter始终是120),同时如果Stopwatch暂停后继续,可能出现判断逻辑混乱。
正确改写方案
维护一个上次执行操作的时间戳,每次Timer触发时计算当前Stopwatch的时间与上次执行时间的差值,达到120秒就执行操作并更新时间戳,既避免重复触发,也能保证每两分钟执行一次:
Timer timer = new Timer(1000); Stopwatch stopwatch = new Stopwatch(); // 记录上次执行操作的时间(以秒为单位) double lastExecuteTime = 0; public MainPage() { InitializeComponent(); MainFunctionTimer(); DeviceDisplay.KeepScreenOn = true; } bool Value = false; string Time = "00:00:00"; private void MainFunctionTimer() { MainTimer.Text = Time; stopwatch = new Stopwatch(); timer.Interval = 500; timer.Elapsed += OnTimerElapsed; } private void OnTimerElapsed(object sender, ElapsedEventArgs e) { Application.Current.Dispatcher.BeginInvokeOnMainThread(() => { var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; MainTimer.Text = stopwatch.Elapsed.ToString(@"hh\:mm\:ss"); // 判断距离上次执行是否超过/等于120秒 if (elapsedSeconds - lastExecuteTime >= 120) { // do sth - 这里写你的操作逻辑 // 更新上次执行时间为当前时间 lastExecuteTime = elapsedSeconds; } }); } private void Start_Stop_Butt_Clicked(object sender, EventArgs e) { if (Value == false) { Value = true; stopwatch.Start(); timer.Start(); } else { Value = false; stopwatch.Stop(); timer.Stop(); } } private void Reset_Clicked(object sender, EventArgs e) { stopwatch.Reset(); MainTimer.Text = Time; // 重置上次执行时间,避免恢复计时后立即触发操作 lastExecuteTime = 0; }
额外说明
- 这种方式不依赖精确的秒数匹配,通过时间差判断避免了Timer间隔导致的重复触发或漏触发问题。
- 重置Stopwatch时同时重置
lastExecuteTime,确保下次启动计时时重新开始计算两分钟周期。
内容的提问来源于stack exchange,提问作者Marsjanin
相关产品推荐
相关产品推荐

