C# WPF中使用Threading.Timer实现循环数秒后停止如何解决
问题根因
你在Timer_Start方法中声明的Timer是局部变量,方法执行结束后没有任何持有该Timer实例的存活引用,会被.NET垃圾回收器判定为可回收对象,回收后定时器自然就停止触发回调,这就是为什么代码只能运行几秒、触发几次Tick就失效的核心原因。
你之前尝试无限循环导致程序无法启动,是因为把循环逻辑写在了UI线程上,直接阻塞了UI消息循环,窗口自然无法正常加载、响应操作。
修复方案
方案1:修正现有System.Threading.Timer的写法
将Timer声明为窗口类的实例字段,保证它的生命周期和当前窗口一致,不会被意外回收:
// 声明为类实例字段,而非方法内局部变量 private Timer _coinTimer; private int coins = 0; private int cps = 1; // 每秒自动增加的金币数,可根据需求调整 public void Timer_Start() { _coinTimer = new Timer(Tick, null, 100, 1000); } public MainWindow() { InitializeComponent(); Timer_Start(); } public void Tick(object stateInfo) { coins += cps; // 跨线程更新UI必须通过Dispatcher调度到UI线程执行,这部分你的写法是对的 this.Dispatcher.Invoke(() => { Score_Update(); }); } // 窗口关闭时释放Timer资源,避免内存泄漏 protected override void OnClosed(EventArgs e) { _coinTimer?.Dispose(); base.OnClosed(e); }
方案2:使用WPF原生DispatcherTimer(更适配WPF场景)
WPF内置的DispatcherTimer运行在UI线程上,不需要手动做跨线程调度,写法更简洁,也不会出现跨线程访问UI的异常,做客户端定时逻辑优先选这个:
private DispatcherTimer _coinTimer; private int coins = 0; private int cps = 1; public void Timer_Start() { _coinTimer = new DispatcherTimer(); _coinTimer.Interval = TimeSpan.FromSeconds(1); // 设置触发间隔为1秒 _coinTimer.Tick += CoinTimer_Tick; _coinTimer.Start(); } private void CoinTimer_Tick(object sender, EventArgs e) { coins += cps; Score_Update(); // 运行在UI线程,无需额外调用Dispatcher.Invoke } public MainWindow() { InitializeComponent(); Timer_Start(); } protected override void OnClosed(EventArgs e) { _coinTimer?.Stop(); base.OnClosed(e); }
开发注意点
- WPF的UI控件有严格的线程亲和性,只有创建控件的UI线程才能直接访问、修改控件属性,非UI线程操作控件必须通过
Dispatcher调度。 - 永远不要在UI线程上写无限循环、
Thread.Sleep这类阻塞逻辑,会卡住UI消息泵,导致程序无响应。 - 所有实现了
IDisposable的对象(比如System.Threading.Timer),不需要使用时要主动调用Dispose释放资源。
内容的提问来源于stack exchange,提问作者Yuri O
相关产品推荐
相关产品推荐

