首先,我对我的英语水平感到非常抱歉。
我目前正在通过 dotnet core 3.1 blazor 开发一个 Web 项目。
如下面的源代码所示,我使用 IJSRuntime 调用需要很长时间的 Javascript 函数。
[Inject]
IJSRuntime JSRuntime { get; set; }
private async Task BtnDisplay()
await JSRuntime.InvokeVoidAsync("RefreshWebJS", Data);
}
Javascript 函数需要很长时间,所以我添加了下面的源代码来添加微调器。
private async Task BtnDisplay()
{
showLoadingImg = true; // add
await JSRuntime.InvokeVoidAsync("RefreshWebJS", Data);
showLoadingImg = false;
}
在razor页面上定义了一个微调器,如下:
@if (showLoadingImg == true)
{
<div style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; text-align: center;">
<img src="/images/LoadingImg.gif" style="position: absolute; top: 50%; left: 50%;" />
</div>
}
“StateHasChanged()”或“await InvokeAsync(() => StateHasChanged())”也不起作用。
当我使用 Task 而不是 JSRuntime 时,效果很好。
await Task.Delay(1000);
为什么我使用 JSRuntime.InvokeVoidAsync 时不起作用?
谢谢您,很抱歉阅读困难的英语。
private async Task BtnDisplay()
{
showLoadingImg = true; // add
await Task.Delay(1);
await JSRuntime.InvokeVoidAsync("RefreshWebJS", Data);
showLoadingImg = false;
}
Blazor 在异步任务中完成第一个
Task
时自动重新渲染。因此,如果第一个 await
是您长时间运行的进程,则在完成之前它不会重新渲染。
添加Task
是一种允许在长时间运行的进程之前进行渲染的简单方法。
进一步阅读:https://github.com/dotnet/aspnetcore/issues/22159这是 Blazor 工作方式的已知功能,Blazor 的创建者也在该线程中推荐了这种方法(尽管他更喜欢
await Task.Delay(1)
- 我总是忘记使用!)
await Task.Yield()
:
await InvokeAsync(StateHasChanged)
它比 Magoo 先生提出的
private bool ShowLoading = false;
private void HandleButtonClick()
{
ShowLoading = true;
Task.Run(async () => await CallLongRunningJs())
.ContinueWith(t => { ShowLoading = false; InvokeAsync(StateHasChanged); });
}
private async Task CallLongRunningJs()
{
await jsRuntime.InvokeVoidAsync("longRunningJsFunc", "data...");
}
的方法更冗长,但我认为为了完整性起见,最好在这里提及这一点。
中有一个私有属性,其中包含Js初始化时的值(IsInitialized)。
Task.Yield()
我在 .Net 8 中多次测试过它,它可以正常工作,但在断开连接时会出现一些错误。似乎 .Net 9 中会有一个功能来处理这些问题。目前,最好的答案是使用 Try catch。