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

如何让DispatcherTimer在MessageBox弹出时继续倒计时

解决DispatcherTimer被MessageBox阻塞的问题

嘿,这个问题我之前在做WPF项目时也碰到过!核心原因很简单:MessageBox是模态对话框,它会彻底阻塞UI线程的消息循环——而你的DispatcherTimer是依赖UI线程的Dispatcher来触发回调的,所以弹窗期间计时器自然就“停摆”了,直到用户关闭弹窗,UI线程的消息循环恢复,计时器才会继续走。

下面给你一个最靠谱的解决方案:

改用后台线程计时器(System.Timers.Timer)

System.Timers.Timer的回调是在ThreadPool线程中执行的,完全独立于UI线程,所以即使UI线程被MessageBox阻塞,它依然会按时触发。只需要注意在更新UI和显示MessageBox时,通过Dispatcher切回UI线程即可。

完整代码示例

首先声明变量:

private TimeSpan _time = TimeSpan.FromSeconds(60);
private System.Timers.Timer _timer;

然后初始化计时器:

// 初始化计时器,设置1秒间隔
_timer = new System.Timers.Timer(1000);
// 绑定回调事件
_timer.Elapsed += OnTimerElapsed;
// 启动计时器
_timer.Start();

接着实现回调方法:

private void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // 在后台线程更新剩余时间(不需要UI权限)
    _time = _time.Subtract(TimeSpan.FromSeconds(1));

    // 所有涉及UI操作的代码必须通过Dispatcher切回UI线程
    Application.Current.Dispatcher.Invoke(() =>
    {
        // 更新界面上的计时器文本
        O2_Timer.Text = _time.ToString("c");

        // 检查是否需要弹出提示
        if (_time == TimeSpan.FromSeconds(30))
        {
            MessageBox.Show("Timer is at 30 seconds!");
        }
        else if (_time == TimeSpan.Zero)
        {
            MessageBox.Show("Time's up!");
            // 时间到了记得停止计时器
            _timer.Stop();
            // 释放计时器资源(可选,根据场景)
            _timer.Dispose();
        }
    });
}

注意事项

  • 记得在窗口关闭或者不再需要计时器时,调用_timer.Stop()和_timer.Dispose(),避免内存泄漏。
  • 如果你的场景中无法获取Application.Current(比如非WPF应用或者多窗口特殊场景),可以用控件自身的Dispatcher,比如O2_Timer.Dispatcher来代替。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:59:54