Blazor WASM 中的意外 UI 绑定行为

Unexpected UI binding behavior in Blazor WASM

我 运行 在 Blazor WASM 和 Blazor 服务器之间的 UI 绑定行为中出现了意想不到的(且无法解释的)差异。给定以下 razor 组件,“发送”按钮在请求期间被正确禁用,在 Blazor 服务器和 Blazor WASM 中:

<MudButton Disabled="isProcessing" OnClick="Submit">Send</MudButton>

@code {
    private bool isProcessing;

    private async Task Submit()
    {
        isProcessing = true;
        var contacts = await Mediator.Send(getContacts);
        isProcessing = false;
    }    
}

在向提交方法添加第二个等待调用 (IsValidAsync()) 后,按钮现在 在 Blazor WASM 请求期间保持启用状态,我认为这是错误的.在 Blazor Server 中,它仍然按预期被禁用:

private async Task Submit()
{
    if (await validator.IsValidAsync())
    {
        isProcessing = true;
        var contacts = await Mediator.Send(getContacts);
        isProcessing = false;
    }
}

是否有明确的理由说明为什么这种绑定在 Blazor WASM 中不起作用?或者这是 Blazor 中的明显错误?

我很惊讶它的行为不同,但服务器和 WASM 之间存在显着差异,这可以解释发生了什么。我对 MudBlazor 不是很熟悉,所以我不确定 MudBlazor 的内部结构是如何工作的。

不同之处在于浏览器只有一个线程用于所有操作。服务器实例上有多少服务器就有多少可用,几乎所有情况都不止一个。

尝试:

private async Task Submit()
{
    isProcessing = true;
    if (await validator.IsValidAsync())
    {
        var contacts = await Mediator.Send(getContacts);
    }
    isProcessing = false;
}

private async Task Submit()
{
    if (await validator.IsValidAsync())
    {
        isProcessing = true;
        await InvokeAsync(StateHasChanged);
        var contacts = await Mediator.Send(getContacts);
        isProcessing = false;
    }
}

事件处理程序基本上是这样做的:

var task = Submit();
StateHasChanged();
if (!task.IsCompleted || !task.IsCanceled)
{
  await task;
  StateHasChanged();
}

您可以在 ComponentBase 中看到这种模式。它说如果任务产生,那么我们更新 UI,等待它完成,然后再次更新 UI。如果它没有产生,那么我们会在它完成后更新 UI。我的服务器和 WASM 代码的行为相同 - 当然你的不同。

您的代码在 if (await validator.IsValidAsync()) 中产生,因此第一个 StateHasChangedisProcessing 设置之前被调用。

规则是您可以免费获得 2 次隐含的 StatehasChanged() 调用,1 次在您的事件处理程序之前,1 次在您的事件处理程序之后。

所以你在第一个 await 中得到一个 'free update' 但是当你的代码中有更多步骤(需要输出)时你需要帮助:

private async Task Submit()
{
   if (await validator.IsValidAsync())  // consumes the first StateHasChanged
   {
      isProcessing = true;

      StateHasChanged();    // request an update

      var contacts = await Mediator.Send(getContacts); // update UI in background
      isProcessing = false;     
   }
   // one implied StateHasChanged for free again
}

这个模式应该用在Server和Wasm上。原始代码在服务器上为您工作的原因尚不清楚。它可能是来自 IsValidAsync() 的侥幸,具有非异步代码路径。