You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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) {}
    }
}

修复效果验证

  1. 间隔计算符合要求:自定义代码执行耗时会被计入总间隔,执行完成后仅等待剩余时长就进入下一轮执行
  2. 停止响应及时:点击停止按钮后会立刻触发取消信号,正在等待的任务会直接中断,不会再执行多余的自定义代码
  3. UI线程无卡顿:所有等待逻辑都在异步线程执行,UI操作不会被阻塞

内容的提问来源于stack exchange,提问作者Amit Gabay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 04:15:04