我正在制作一个 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 代码上,但第一次不会。为什么会这样?
注意:我不希望使用
Task.Delay
或者 Task.Run(...)
来解决问题,因为这些线程和 UI 刷新线程之间存在竞争关系,所以这不是可靠的解决方案。我正在寻找关于 StateHasChanged()
行为的答案,或者通过使用诸如 PropertyChanged
或 EventCallback
事件并将按钮作为子组件来实现绕过。编辑:经过一些测试,似乎只有在
Task
上进行 await
操作后,StateHasChanged()
才会触发组件的重新渲染。可以轻松测试将 result = await _LogInService.TryLogIn(logInForm);
行注释掉或将 IsDisabled = ...
更改为 await new Task.Run(() => { IsDisabled = ...})
。现在我已经有了一些解决方法,但我仍然想知道为什么会出现这样的特性。难道 StateHasChanged()
不应该在任何操作后都重新渲染?或者它只认为只有 async
操作(因此主要是服务器调用)才能改变 UI 中的内容?
StateHasChanged()
如何工作或如何使用事件来实现它的答案,而不是一个解决方法。 - PepperTigerTryLogIn()
不是一个虚假的异步函数,它使用SignInManager
来检查并登录用户。 - PepperTiger