C# WinForm定时执行代码(耗时计入间隔)及即时停止实现问题
问题根源
- 间隔计算逻辑错误:原有
System.Windows.Forms.Timer的触发逻辑是等待设定间隔后才执行代码,执行完成后再重新开始计时,自定义代码的执行耗时不会被计入总间隔 - 停止逻辑失效:每次点击开始按钮都会重复注册
Tick事件回调,导致单次触发会执行多次自定义代码;停止按钮仅修改了按钮可见性,没有主动停止定时器、修改退出标记,消息队列中积压的Tick事件还会继续触发 - UI线程阻塞:
button1_Click中的while+Application.DoEvents()写法会阻塞UI主线程,导致状态更新不及时
解决方案
改用异步任务+取消令牌的实现方案,既能精确计算间隔,也能实现秒停效果,同时不会阻塞UI线程。
修复后完整代码
using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp1 { public partial class Form1 : Form { // 总间隔时长,单位毫秒 private const int TotalInterval = 60000; // 取消令牌源,用于控制任务停止 private CancellationTokenSource _cts; public Form1() { InitializeComponent(); // 初始状态只显示开始按钮 button1.Visible = true; button2.Visible = false; } private async void button1_Click(object sender, EventArgs e) { // 切换按钮状态 button1.Visible = false; button2.Visible = true; _cts = new CancellationTokenSource(); try { // 循环执行直到收到取消信号 while (!_cts.IsCancellationRequested) { // 记录当前执行开始时间 var startTime = DateTime.Now; // -------------------------- // 此处替换为你的自定义代码 // 示例:模拟执行30秒 await Task.Delay(30000, _cts.Token); // -------------------------- // 计算本次执行耗时 var elapsed = (DateTime.Now - startTime).TotalMilliseconds; // 计算需要等待的剩余时间 var waitTime = TotalInterval - elapsed; // 剩余时间大于0就等待,否则直接进入下一轮执行 if (waitTime > 0 && !_cts.IsCancellationRequested) { await Task.Delay((int)waitTime, _cts.Token); } } } catch (OperationCanceledException) { // 收到取消信号后正常退出,不需要处理异常 } finally { _cts.Dispose(); _cts = null; } } private void button2_Click(object sender, EventArgs e) { // 发送取消信号,立刻终止异步循环 _cts?.Cancel(); // 切换按钮状态 button2.Visible = false; button1.Visible = true; } // 其余空事件处理方法可直接删除 private void Form1_Load(object sender, EventArgs e){} private void textBox1_TextChanged(object sender, EventArgs e){} private void agTextBox1_Load(object sender, EventArgs e) {} } }
修复效果验证
- 间隔计算符合要求:自定义代码执行耗时会被计入总间隔,执行完成后仅等待剩余时长就进入下一轮执行
- 停止响应及时:点击停止按钮后会立刻触发取消信号,正在等待的任务会直接中断,不会再执行多余的自定义代码
- UI线程无卡顿:所有等待逻辑都在异步线程执行,UI操作不会被阻塞
内容的提问来源于stack exchange,提问作者Amit Gabay
相关产品推荐
相关产品推荐

