【发布时间】:2020-03-14 21:39:23
【问题描述】:
我正在制作一个 Blazor 服务器端项目,我想制作一个在单击后停用的按钮,但不使用 <button> 的 disabled 属性。代码很简单:
@functions {
LogInForm logInForm = new LogInForm();
bool IsDisabled;
SignInResult result;
protected override void OnInitialized()
{
IsDisabled = false;
}
async Task TryLogIn()
{
IsDisabled = true;
StateHasChanged();
result = await _LogInService.TryLogIn(logInForm);
Console.WriteLine("Logging status : " + (result.Succeeded ? "Sucess" : "Failure"));
IsDisabled = false;
StateHasChanged();
}
}
出于奇怪的原因,第一个 StateHasChanged 没有触发,但第二个确实会重新呈现页面。通过进入调试模式并进入StateHasChanged() 方法可以很容易地进行测试。在第二次调用时,它确实在进入方法后停止在 HTML 代码上,但不是第一次。
为什么会这样?
NB : 我不是在寻找仅使用 Task.Delay 或 Task.Run(...) 的任何解决方法,因为这些线程和 UI 刷新线程之间存在竞争条件,因此不是一个可靠的解决方案。我正在寻找有关StateHasChanged() 行为的答案或使用PropertyChanged 或EventCallback 之类的事件并将按钮作为子组件的解决方法。
编辑:经过一些测试,似乎StateHasChanged() 仅在对Task 执行await 操作后触发组件的重新渲染。可以通过在result = await _LogInService.TryLogIn(logInForm); 行中添加评论或将IsDisabled = ... 更改为await new Task.Run(() => { IsDisabled = ...}) 来轻松测试它。我现在有一些解决方法,但我仍然想知道为什么这是一个功能。 StateHasChanged() 不应该在任何操作后重新渲染吗?或者它认为只有 async 操作(主要是服务器调用)可以改变 UI 中的某些内容?
【问题讨论】:
-
这能回答你的问题吗? Blazor - Display wait or spinner on API call
-
不,因为您的答案似乎仅依赖于
Task.Delay(1)解决方法,在 Nota Bene 中已经说过,由于竞争条件,它不可靠。此外,我更想知道StateHasChanged()是如何工作的,或者如何通过使用事件来做到这一点,而不是解决方法。 -
这是旧的 DoEvents() 问题的新伪装。
-
真正的问题可能是_service.TryLogIn(),它真的是异步的吗?还是只是假装?
-
不,
TryLogIn()不是假异步,因为它使用SignInManager来检查和登录用户。
标签: c# asp.net razor blazor blazor-server-side