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

Blazor Server应用定时器无法周期性执行PLC数据读取问题

问题分析与修复方案

你的Blazor Server定时器不工作、计数器始终为0的问题,主要由以下几个代码错误导致:

核心问题点

  1. 变量名不匹配:定时器事件里更新的是counter_CNC_status,但页面绑定的是counter_timer,两者不一致导致页面显示永远为0。
  2. 非UI线程更新状态:System.Timers.Timer的Elapsed事件在后台线程触发,直接调用StateHasChanged()无法触发Blazor组件的UI渲染,因为Blazor要求状态更新必须在UI同步上下文执行。
  3. 异步方法规范问题:Read_CNC_Status使用async void,这在Blazor中会导致异常无法被捕获,应该使用async Task。
  4. 重复绑定事件风险:多次点击按钮会重复添加Elapsed事件处理程序,导致定时器触发逻辑混乱。
  5. 未释放资源:组件销毁时未释放定时器,会引发内存泄漏。

修复后的完整代码

Razor页面代码

@inject PLCService PLCService
@implements IDisposable

<button @onclick="Read_CNC_Status">Read PLC Data</button>
<span>@counter_timer</span>

代码后置文件(Read_PLC_Data.razor.cs)

using System.Timers;
using Microsoft.AspNetCore.Components;

public partial class Read_PLC_Data : IDisposable
{
    public int counter_timer = 0; 
    private System.Timers.Timer? _timer;

    [Inject]
    public PLCService PLCService { get; set; } = default!;

    public async Task Read_CNC_Status()
    {
        PLCService.Connect_PLC();
        InitializeTimer();
    }

    private void InitializeTimer()
    {            
        // 先销毁旧定时器,避免重复绑定事件
        _timer?.Dispose();
        
        _timer = new System.Timers.Timer(1000);
        _timer.Elapsed += OnTimedEvent;
        _timer.AutoReset = true; // 显式设置自动重置,确保每秒触发一次
        _timer.Enabled = true;
        counter_timer = 0;
    }

    private async void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        // 通过InvokeAsync将逻辑切换到UI线程执行
        await InvokeAsync(() =>
        {
            PLCService.Read_PLC_Data();            
            counter_timer += 1; // 修正变量名,与页面绑定一致
            if(counter_timer >= 30)
            {
                counter_timer = 0;
                _timer?.Enabled = false;
            }
            StateHasChanged();
        });
    }

    // 实现IDisposable,组件销毁时释放定时器资源
    public void Dispose()
    {
        _timer?.Dispose();
    }
}

关键修复说明

  • 变量名统一:将事件中的计数器变量改为counter_timer,与页面绑定的变量保持一致,确保页面能正确显示计数。
  • UI线程同步:使用InvokeAsync包裹状态更新逻辑,强制在UI线程执行,保证StateHasChanged()能触发组件重新渲染。
  • 异步方法规范:把Read_CNC_Status改为async Task,符合Blazor的异步处理要求,避免异常丢失。
  • 定时器资源管理:每次初始化定时器前先销毁旧实例,防止重复绑定事件;实现IDisposable接口,组件销毁时释放定时器,避免内存泄漏。
  • 显式配置定时器:设置AutoReset = true,明确定时器每秒自动触发一次,逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 22:57:21