Blazor WebAssembly:如何在长时间运行、非异步过程中更新UI



我有一些复杂的计算需要一段时间才能完成。我可以让UI在计算过程中重新渲染,但不能正确更新结果。

请注意,计算是而不是本质上异步的,将它们封装在Task.Run中似乎没有帮助。以下是演示该问题的代码的简化版本:

@page "/AsyncTest"
<button type="button" class="btn btn-primary" @onclick="@(e => RunOnClick(e))">Run</button>
<br />
<div>Percent Complete = @PercentComplete %</div>
@code {
    private int PercentComplete = 0;
    private async Task RunOnClick(MouseEventArgs e) {
        for (PercentComplete = 0; PercentComplete < 100; PercentComplete += 20) {
            System.Console.WriteLine($"LongCalculation: PercentComplete = {PercentComplete}");
            await Task.Run(() => Calculation()); // Does not work.
            //await CalculationAsync();          // This works.
            StateHasChanged();
        }
    }
    private void Calculation() => System.Threading.Thread.Sleep(500);
    private async Task CalculationAsync() => await Task.Delay(500);
    protected override void OnAfterRender(bool firstRender) {
        System.Console.WriteLine($"OnAfterRender: PercentComplete = {PercentComplete}");
    }
}

单击该按钮时,UI上的"完成百分比"不会更新,直到所有处理完成,即从0%到100%,其间没有任何步骤。如果我使用异步版本CalculationAsync(),UI会按预期更新。

这是控制台输出:

blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 0
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 0
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 20
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 20
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 40
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 40
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 60
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 60
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 80
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 80
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 100

这表明UI正在重新渲染,PercentComplete属性正在随着计算的进行而更新。然而,由于某种原因,UI实际上并没有被更改。我不确定Blazor是否以某种方式缓存了PercentComplete的值,或者它是否没有意识到它已经改变并跳过了渲染的那一部分。

你知道我该怎么做吗?

注:此问题与17069489不同。虽然不明显,但这个问题涉及异步的任务。

在Task.Run((中封装同步版本将在Blazor/Server中工作,但在Blazor/Wasm中无效。WebAssembly在单个线程上运行,这仍然是Browser/Wasm的限制。

当Blazor在Wasm 2上运行并获得真正的线程时,这一问题可能会在未来得到解决。我不知道它的预产期。

同时,通过一个额外的Task使循环至少有点异步。Delay((:

for (PercentComplete = 0; PercentComplete < 100; PercentComplete += 20) 
{
  System.Console.WriteLine($"LongCalculation: PercentComplete = {PercentComplete}");
   Calculation(); // Make the steps as small as possible, Task.Run is of no use
   StateHasChanged();    
   await Task.Delay(1);  // give the UI some time to catch up
}

相关内容

  • 没有找到相关文章

最新更新