首先,我对我的英语技能感到非常抱歉。
我目前正在通过dotnetcore3.1blazor开发一个网络项目。
在下面的源代码中,我使用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;
}
剃刀页面上的微调器定义如下:
@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.InvokeVoidSync时它不起作用?
谢谢你,很抱歉你读到了难听的英语。
private async Task BtnDisplay()
{
showLoadingImg = true; // add
await Task.Delay(1);
await JSRuntime.InvokeVoidAsync("RefreshWebJS", Data);
showLoadingImg = false;
}
Blazor在异步任务中await
的第一个Task
完成时自动重新渲染。
因此,如果第一个Task
是一个长时间运行的进程,那么在它完成之前,它不会重新渲染。
添加await Task.Delay(1)
是允许在长时间运行的进程之前进行渲染的一种简单方法。
进一步阅读:https://github.com/dotnet/aspnetcore/issues/22159
这是Blazor工作方式的已知特征,Blazor的创建者也在该线程中推荐了这种方法(尽管他更喜欢await Task.Yield()
——我总是忘记使用它!(
如前所述,还有一种使用同步事件处理程序的方法,它在新任务中启动JS Interop,然后立即返回。您必须确保在这个新任务完成后,使用await InvokeAsync(StateHasChanged)
:重新同步它
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...");
}
它比Magoo先生提出的Task.Yield()
方法更详细,但为了完整性,我认为在这里提到这一点是很好的。