我有一个组件需要每 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/