Blazor WebAssembly中Timer触发StateHasChanged为何自动执行页面内嵌函数?
问题解答
运行逻辑说明
Blazor的组件重渲染机制直接导致了你观察到的现象:
- 任何触发组件重渲染的操作(包括手动调用
StateHasChanged()、用户交互操作、框架内置事件回调)都会让Blazor重新执行当前组件Razor模板内的所有嵌入式C#表达式,计算得到最新的视图内容后完成DOM更新。 - 你在模板中写的
@((MarkupString)addText())属于典型的嵌入式渲染表达式,本质就是告知Blazor每次渲染时都要执行该函数获取要输出的内容,属于渲染阶段的隐式调用,不需要你在业务代码中显式调用。而addText()内部包含sometext++的自增逻辑,所以每次Timer触发StateHasChanged()启动重渲染时,变量都会自动加1。
修改后不再自增的原因
你将代码替换为@((MarkupString)sometext.ToString())后,该表达式仅执行读取sometext值、转换为字符串的纯计算逻辑,没有任何修改变量的操作,自然不会触发自增。
注意事项
- Razor模板内的嵌入式表达式应该保持无副作用的纯计算属性,不要在其中编写修改组件状态、调用外部IO等逻辑,否则每次重渲染都会触发副作用,导致预期外的行为。
- 由于
Timer.Elapsed事件默认在线程池线程触发,如果你后续遇到跨线程渲染异常,可以把StateHasChanged()调用包装在InvokeAsync()中,示例如下:
private void TimerOnElapsed(object sender, ElapsedEventArgs e) { InvokeAsync(StateHasChanged); }
该方法可以将渲染操作调度到Blazor的UI同步上下文执行,规避多线程冲突。
内容的提问来源于stack exchange,提问作者E.D.
相关产品推荐
相关产品推荐

