简体   繁体   English

Blazor WASM 中的意外 UI 绑定行为

[英]Unexpected UI binding behavior in Blazor WASM

I have run into an unexpected (and inexplicable) difference in UI binding behavior between Blazor WASM and Blazor server.我在 Blazor WASM 和 Blazor 服务器之间的 UI 绑定行为中遇到了意外(且莫名其妙)的差异。 Given the following razor component, the "Send" button is correctly disabled during the request, in both Blazor Server and Blazor WASM:鉴于以下 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;
    }    
}

After adding a second awaited call ( IsValidAsync() ) to the Submit-method, the button now stays enabled during the request in Blazor WASM, which I consider wrong.在向提交方法添加第二个等待调用( IsValidAsync() )后,该按钮现在在 Blazor WASM 中的请求期间保持启用状态,我认为这是错误的。 In Blazor Server it still gets disabled as expected:在 Blazor 服务器中,它仍然按预期被禁用:

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

Is there a clear reason as to why this kind of binding would not work in Blazor WASM?为什么这种绑定在 Blazor WASM 中不起作用有明确的原因吗? Or is this a clear bug in Blazor?或者这是 Blazor 中的一个明显错误?

The rule is that you get 2 implied StatehasChanged() calls for free, 1 before and 1 after your eventhandler.规则是您可以免费获得 2 个隐含的 StatehasChanged() 调用,1 个在事件处理程序之前和 1 个之后。

So you get a 'free update' in the first await but when you have more steps in your code (that require output) you need to help:因此,您在第一次等待中获得了“免费更新”,但是当您的代码中有更多步骤(需要输出)时,您需要帮助:

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
}

This pattern should be used on Server and Wasm.这种模式应该用在 Server 和 Wasm 上。 The reason why the original code worked for you on Server is unclear.原始代码在服务器上为您工作的原因尚不清楚。 It probably is a fluke from IsValidAsync() having a non-async code path.这可能是来自 IsValidAsync() 的侥幸,具有非异步代码路径。

I'm suprised it behaves differently, but there is a significant different between Server and WASM that may explain what's going on.我很惊讶它的行为不同,但 Server 和 WASM 之间存在显着差异,这可以解释发生了什么。 I'm not fully familiar with MudBlazor, so I'm not sure how the MudBlazor internals work exactly.我对 MudBlazor 并不完全熟悉,所以我不确定 MudBlazor 内部是如何工作的。

The difference being that the browser has only a single thread for all operations.不同之处在于浏览器对于所有操作只有一个线程。 Server as as many as are available on the server instance, which is almost all cases is more than one.服务器尽可能多的可用在服务器实例上,这几乎在所有情况下都不止一个。

Try:尝试:

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

or或者

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

The event handler basically does this:事件处理程序基本上是这样做的:

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

You can see this pattern in ComponentBase .您可以在ComponentBase中看到这种模式。 It says if the task yields then we update the UI, wait for it to complete and then update the UI again.它说如果任务成功,那么我们更新 UI,等待它完成,然后再次更新 UI。 If it doesn't yield then we update the UI once it completes.如果它没有产生,那么我们会在它完成后更新 UI。 Both my Server and WASM codes behave the same -nit sure whay yours is different.我的服务器代码和 WASM 代码的行为相同 - 确定您的代码有何不同。

Your code yields in if (await validator.IsValidAsync()) and thus the first StateHasChanged gets called before isProcessing is set.您的代码在if (await validator.IsValidAsync())中产生,因此在设置isProcessing之前调用第一个StateHasChanged

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM