Blazor中用Timer控制布尔值隐藏GIF致页面冻结问题求助
Blazor中Timer导致应用冻结的解决方法
问题根源
你的代码存在三个核心问题:
- 线程安全问题:
System.Timers.Timer的Elapsed事件在后台线程触发,直接修改UI状态check=false并调用StateHasChanged()会引发跨线程操作,导致应用异常。 - 重复执行逻辑:把Timer的初始化、启动、事件绑定写在
@if(check)渲染块中,每次组件渲染都会重复执行这些操作,造成Timer实例堆积、事件重复绑定,最终引发冻结。 - 逻辑顺序错误:
StateHasChanged()和timer.Stop()没有放在事件委托内部,而是在渲染时直接执行,根本无法实现3秒后隐藏GIF的效果。
正确实现方式
方式一:用Task.Delay异步处理(推荐,最简单安全)
Blazor中处理延迟操作,优先用异步方法配合Task.Delay,天然适配UI线程,无需额外Timer:
@using blazorTestApp.Client.Entities @code { public Books CreatedBook { get; set; } = new Books(); bool check = false; public async void OnSubmit() { check = true; StateHasChanged(); // 立即更新UI显示GIF await Task.Delay(3000); // 等待3秒 check = false; StateHasChanged(); // 更新UI隐藏GIF } } @if(check) { <img class="Thanks" src="https://gifsec.com/wp-content/uploads/2022/09/thank-you-gif-1.gif"/> }
方式二:用System.Threading.Timer(适合复杂定时场景)
如果必须使用Timer,推荐用System.Threading.Timer,并通过InvokeAsync确保UI线程安全:
@using blazorTestApp.Client.Entities @using System.Threading @implements IDisposable @code { public Books CreatedBook { get; set; } = new Books(); bool check = false; private Timer _timer; public void OnSubmit() { check = true; StateHasChanged(); // 3秒后触发一次回调,不再重复执行 _timer = new Timer(_ => { // 用InvokeAsync确保在UI线程更新状态 InvokeAsync(() => { check = false; StateHasChanged(); _timer.Dispose(); // 及时释放Timer资源 }); }, null, 3000, Timeout.Infinite); } // 组件销毁时清理Timer,避免内存泄漏 public void Dispose() { _timer?.Dispose(); } } @if(check) { <img class="Thanks" src="https://gifsec.com/wp-content/uploads/2022/09/thank-you-gif-1.gif"/> }
重要提示
- Blazor所有UI状态更新必须在UI线程执行,跨线程操作务必用
InvokeAsync()包裹。 - 不要在组件渲染逻辑中创建或操作Timer,这类逻辑应该放在事件处理方法(比如
OnSubmit)里。 - 使用Timer时,一定要在组件销毁时释放资源,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Saucter
相关产品推荐
相关产品推荐

