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

问题描述 投票:0回答:1

我有一个组件需要每 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();
        }
    }
}
timer blazor blazor-server-side
1个回答
2
投票

如果我将代码放入

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;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.