我正在Blazor服务器端页面中设置计时器。目标是每x秒调用一次API,并根据返回值更新UI。
我得到了这个代码:
private string Time { get; set; }
protected override void OnInitialized()
{
var timer = new System.Threading.Timer((_) =>
{
Time = DateTime.Now.ToString();
InvokeAsync(() =>
{
StateHasChanged();
});
}, null, 0, 1000);
base.OnInitialized();
}
这个效果很好。UI每秒都会使用新的时间值进行更新。然而,我不知道如何调用异步任务来获取值。我想更换线路:
Time = DateTime.Now.ToString();
使用一行调用以下函数:
private async Task<string> GetValue()
{
var result = await _api.GetAsync<StringDto>("/api/GetValue");
return result.Text;
}
我试过这条线:
Time = GetValue().Result;
但我收到以下错误:
The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.
我需要做些什么来调用异步方法?
谢谢大家!
您可能不想调用((GetValue((,这将毫无意义。你可以实现这样的定时器:
System.Threading.Timer timer;
protected override void OnInitialized()
{
timer = new System.Threading.Timer(async _ => // async void
{
Time = await GetValue();
// we need StateHasChanged() because this is an async void handler
// we need to Invoke it because we could be on the wrong Thread
await InvokeAsync(StateHasChanged);
}, null, 0, 1000);
}
我用了一个字段来存储Timer,因为你应该处理它,把它添加到Razor部分:
@implements IDisposable
这个到代码:
public void Dispose()
{
timer?.Dispose();
}
在.NET 6中,您可以按如下方式使用PeriodicTimer类
私有字符串时间{get;set;}
protected override async void OnAfterRender(bool firstRender)
{
if (firstRender)
{
using var periodicTimer = new PeriodicTimer(TimeSpan.FromMinutes(10));
while (await periodicTimer.WaitForNextTickAsync())
{
Time= await GetValue();
await InvokeAsync(StateHasChanged);
}
}
}
运行它而不会永远束缚生命周期方法:
@implements IDisposable
PeriodicTimer periodicTimer = new (TimeSpan.FromMinutes(10));
protected override void OnInitialized()
{
RunTimer(); // fire-and-forget
}
async void RunTimer()
{
while (await periodicTimer.WaitForNextTickAsync()) { .... }
}
public void Dispose()
{
periodicTimer?.Dispose();
}
试试这个代码:
private string Time { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
var timer = new System.Threading.Timer((_) =>
{
InvokeAsync( async () =>
{
Time = await GetValue();
StateHasChanged();
});
}, null, 0, 1000);
}
您的GetValue方法应该是:
private async Task<string> GetValue()
{
return await _api.GetAsync<StringDto>("/api/GetValue");
}