2

首先,我对我的英语水平感到非常抱歉。

我目前正在通过 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;
}

剃须刀页面上的微调器定义如下:

@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 时它不起作用?

谢谢你,很抱歉读到难读的英语。

4

2 回答 2

3
private async Task BtnDisplay()
{
    showLoadingImg = true; // add
    await Task.Delay(1);
    await JSRuntime.InvokeVoidAsync("RefreshWebJS", Data);
    showLoadingImg = false;
}

TaskBlazor 会在您完成第await一个异步任务时自动重新呈现。

因此,如果第一个Task是您长期运行的过程,那么在完成之前它不会重新渲染。

添加await Task.Delay(1)是一种在长时间运行过程之前允许渲染的简单方法。

进一步阅读:https ://github.com/dotnet/aspnetcore/issues/22159

这是 Blazor 工作方式的已知特征,Blazor 的创建者也在该线程中推荐了这种方法(尽管他更喜欢await Task.Yield()- 我总是忘记使用它!)

于 2021-06-16T08:23:35.717 回答
1

正如之前的评论中提到的,还有一种使用同步事件处理程序的方法,它在新任务中启动 JS 互操作并在此之后立即返回。您必须确保在完成后重新同步此新任务,方法是使用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...");
}

它比Task.Yield()Magoo 先生提出的方法更冗长,但为了完整起见,我认为在这里提及这一点是件好事。

于 2021-06-16T09:40:32.400 回答