---更新---
我现在可以说,每次定时器触发失败时,我都会在调试输出中收到以下错误消息。当我得到错误时,计时器100%失败。
Failed to load resource: net::ERR_HTTP2_PROTOCOL_ERROR [https://localhost:44371/_framework/blazor.server.js] Exception thrown: 'Microsoft.AspNetCore.Connections.ConnectionResetException' in Microsoft.AspNetCore.Server.IIS.dll
然而,实时站点(在Windows服务器上(有时也无法触发定时器,所以我不认为这只是VS调试问题。
---/更新---
我的门厅页面上有一个动画svg,持续3秒。我想在3秒钟后显示附加控件:登录按钮;进行一次旅行";等等,所以我添加了一个在OnAfterRender中启动的Timer(也尝试了OnAfterRenderAsync(。
问题是,大约有1/3的时间(随机地,很少有1/20或更多(,计时器的处理程序没有触发,控件也没有显示。我假设这是某种线程竞争条件,但我真的不明白该怎么办。
我试过:
- 使用
async
生命周期事件和处理程序 - CCD_ 3表达等
(注意——我知道我可以使用动画CSS来做这件事,但我现在正在限制计时器的使用(
这里有一些简化的代码:
<MyCoolAnimation / >
@if (ShowControls)
{
// various controls
}
@code {
bool ShowControls;
protected override void OnAfterRender(bool firstRender)
{
if (!firstRender)
{
Timer = new Timer(3000);
Timer.Elapsed += CountDownTimer;
Timer.Start();
}
}
private async void CountDownTimer(Object source, System.Timers.ElapsedEventArgs e)
{
Timer.Stop();
Timer.Dispose();
ShowControls = true;
await InvokeAsync(StateHasChanged);
}
}
在这种情况下,我将避免整个Timer问题。
您可以使用Timer、Dispose模式或InvokeAsync来完成此操作。保持简单:
<MyCoolAnimation / >
@if (ShowControls)
{
// various controls
}
@code {
bool ShowControls;
protected override async Task OnInitializedAsync()
{
ShowControls = false;
await Task.Delay(3_000);
ShowControls = true;
}
}
我对在经过的处理程序内部调用Timer.Dispose()
表示怀疑。但找不到关于它的授权声明。
if (!firstRender)
很奇怪——您会有很多计时器在运行。
这提供了一个答案,Timer = new Timer(3000);
和Timer.Dispose();
部分有一个竞争条件(至少在Blazor服务器上(。
- 确保页面上只有1个Timer实例
- 在OnInitialized((中创建并启动它
- 使用
@implements IDisposable
进行清理
下面是一些示例代码。
(v3(
上次更新:
我已经受够了。谢谢你们的帮助,伙计们!现在,Henk的以下建议有效。我更新了Windows,我认为这就是问题所在——但我仍然无法使Timer版本正常工作。我谨慎乐观地认为,问题出在生命周期上,而不是Timers。
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!ShowControls)
{
await Task.Delay(3000);
ShowControls = true;
StateHasChanged();
}
}
在我看来,在Blazor生命周期内实例化Timer对象可能过于挑剔,无法使其可靠工作。
我唯一的希望是,我使用Timer做的其他事情(比如通过服务弹出排队的消息(不会在5%的时间内中断。