timer - 在blazor服务器中使用PeriodicTimer刷新组件的最佳方法是什么

标签 timer blazor blazor-server-side

我有一个组件需要每 1 分钟显示一次新数据。

我尝试了新的计时器(定期计时器),它工作正常。

现在,我的问题是,

放置 while 循环的最佳位置在哪里?

正确处置PeriodicTimer还需要其他东西吗?

public partial class Index:IDisposable
{
    private readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromMinutes(1));

    protected override async Task OnInitializedAsync()
    {
        await Service.Init();
        while (await _periodicTimer.WaitForNextTickAsync())
        {
            await Service.GetViewModels();
            await InvokeAsync(StateHasChanged);
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
           _periodicTimer.Dispose();
        }
    }
}

最佳答案

如果我将代码放在 Index 中,即状态页面,它永远不会完成加载。

如果我将代码放在另一个页面中,看起来运行正常,但事实并非如此。

问题是 OnInitializedAsync 永远不会完成。它始终在 while 循环中等待。因此,初始组件生命周期的其余部分也没有完成。

作为启动页面,它在初始服务器负载中被锁定。

要解决这个问题,您需要“触发并忘记”计时器循环。

这是一个可以工作的演示组件,以及如何将“旧”计时器与事件处理程序一起使用(我个人会坚持使用)。

@page "/Test"
@implements IDisposable

<h1>Hello</h1>
<div class="m-2">
    Message: @message
</div>
<div class="m-2">
   Timer Message: @timerMessage
</div>
<div class="m-2">
    @state
</div>
@code {
    private System.Timers.Timer timer = new System.Timers.Timer(2000);
    private readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(5));
    private string message = "Starting";
    private string timerMessage = "Starting";
    private string state = "On Init Running";

    // This is broken code 
    //protected override async Task OnInitializedAsync()
    //{
    //    while (await _periodicTimer.WaitForNextTickAsync())
    //    {
    //        message = $"Updated at {DateTime.Now.ToLongTimeString()}";
    //        await InvokeAsync(StateHasChanged);
    //    }
    //}

    protected override void OnInitialized()
    {
        RunTimer();
        state = "On Init complete";

        // Uses System.Timers.Timer
        timer.Elapsed += TimeElapsed;
        timer.AutoReset = true;
        timer.Enabled = true;

    }

    private async void TimeElapsed(object? sender, System.Timers.ElapsedEventArgs e)
    {
        // emulate an async data get
        await Task.Delay(100);
        timerMessage = $"Updated at {DateTime.Now.ToLongTimeString()}";
        await InvokeAsync(StateHasChanged);
    } 

    protected async void RunTimer()
    {
        while (await _periodicTimer.WaitForNextTickAsync())
        {
            // emulate an async data get
            await Task.Delay(100);
            message = $"Updated at {DateTime.Now.ToLongTimeString()}";
            await InvokeAsync(StateHasChanged);
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            _periodicTimer.Dispose();
            timer.Elapsed -= TimeElapsed;
        }
    }
}

关于timer - 在blazor服务器中使用PeriodicTimer刷新组件的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72711306/

相关文章:

java - 线程在倒计时时卡住 UI

c# - 使用自定义对象的 MudBlazor 自动完成 (NullReferenceException)

blazor - 当 ASPNETCORE_ENVIRONMENT 更改为 "Development"以外的任何内容时 - 在 VS 中调试时,Blazor 应用程序看不到来自 razor 类库的资源

asp.net - 当多个 Blazor 应用程序发布到 IIS 时,我们收到 HTTP 错误 500.35 - ASP.NET Core 不支持同一应用程序池中的多个应用程序

c# - 如何使用 Blazor 服务器端制作渐进式 Web 应用程序?

blazor - 如何在同一个 Web 中同时使用 Blazor 客户端和服务器

Java 定时器和 Action 监听器

c++ - 如何在控制台 Win32 应用程序中设置计时器?

android - 计时器结束后如何播放WAV?

.net - 如何从 appsettings 动态设置 Blazor 中授权 View 标记或属性允许的角色或策略?