Pep*_*ger 4 c# asp.net razor blazor blazor-server-side
我正在做Blazor服务器端的项目,我想使一个按钮,desactivate点击后,却没有使用disabled的属性<button>。代码非常简单:
@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();
}
}
Run Code Online (Sandbox Code Playgroud)
出于奇怪的原因,第一个StateHasChanged没有触发,但第二个确实重新呈现页面。通过进入调试模式并进入StateHasChanged()方法,它可以很容易地进行测试。第二次调用时,它会在进入方法后停止在 HTML 代码上,但不是第一次。
为什么这样 ?
注意:我不是在寻找任何使用Task.Delay或Task.Run(...)仅使用的解决方法,因为它在这些线程和 UI 刷新线程之间存在竞争条件,因此它不是一个可靠的解决方案。我正在寻找有关StateHasChanged()行为或解决方法的答案,方法是使用诸如PropertyChanged或之类的事件EventCallback并将按钮作为子组件。
编辑:经过一些测试,似乎StateHasChanged()只有await在对Task. 可以通过添加注释result = await _LogInService.TryLogIn(logInForm);行或更改IsDisabled = ...为来轻松测试它await new Task.Run(() => { IsDisabled = ...})。我现在有一些解决方法,但我仍然想知道为什么这是一个功能。不应该StateHasChanged()在任何操作后重新渲染?或者它认为只有async操作(所以主要是服务器调用)可以改变 UI 中的某些内容?
Blazor 团队即将发布有关 StateHasChanged() 工作原理的文档。
你可以在这里跟踪它:https : //github.com/aspnet/AspNetCore/issues/14591
就目前而言,我认为摘自 github 评论的这个解释是一个很好的解释:
添加对 StateHasChanged 的调用只是将要呈现的组件排队。渲染器决定渲染何时发生。
这可能由 4 种情况触发:
- 初始渲染,引导过程触发根组件及其所有子组件的初始渲染。
- 一个事件,其中处理事件的组件会在事件发生后自动触发新的渲染,如果渲染新的子项或更改其参数,则可能会触发其子项。
- 由于从 InvokeAsync 调用调用 StateHasChanged(本质上是编组回 UI 线程)
- 作为父组件更改子组件参数的结果,当渲染器在子组件上调用 SetParametersAsync 时,这会作为差异过程的一部分发生。
非常清楚,调用 StateHasChanged 只会为组件排队渲染或“将其标记为脏”。
渲染器决定何时以及如何生成渲染。BuildRenderTree 不会产生新的渲染输出,只会在组件被调用时产生新的“V-DOM”定义。
通常,每个渲染批次(这是一起渲染/差异化并发送到 UI 进行更新的组件的集合)渲染一次组件。一个组件在一个批处理中渲染不止一次的情况只有两种:
- 您有一个直接实现 IComponent 并调用 RenderHandle.Render 的组件
- 您在子组件和父组件之间存在循环依赖,这可能会导致父组件作为子组件的一部分重新渲染,从父组件调用某些回调参数作为其初始化的一部分
来源:https : //github.com/aspnet/AspNetCore/issues/15175#issuecomment-544890549
下面通过执行流程来描述重新渲染是如何发生的:
现在,当您在为局部变量 IsDisabled 赋值后调用 StateHasChanged 时,并不会真正更改组件的状态,并且调用 StateHasChanged 没有理由会产生重新渲染。当您调用 StateHasChanged 时,它只是将该组件的呈现请求排队。但没有理由重新渲染......
或者它认为只有异步操作(主要是服务器调用)才能更改 UI 中的某些内容?
它与操作的类型是否为异步无关,除了 OnInitializedAsync 方法之外,在这种情况下,当 OnInitializedAsync 方法完成时会自动调用 StateHasChanged 方法,以使用新数据再次重新渲染 UI由 OnInitializedAsync 方法中执行的异步调用检索。
更新:
您想要的可以通过多种方式完成,其中最简单的方式如下所示:
<input type="button" value="Click me now" disabled="@IsDisabled" @onclick="TryLogIn" />
@code{
bool IsDisabled;
protected override void OnInitialized()
{
IsDisabled = false;
}
async Task TryLogIn()
{
IsDisabled = true;
// Do some async work here...
// Note: Replace your async method with Task.Delay
await Task.Delay(5000);
IsDisabled = false;
}
}
Run Code Online (Sandbox Code Playgroud)
这应该有效...注意:禁用按钮控件的唯一方法是使用禁用属性
无需调用 StateHasChanged 方法。当编译器(编译器)为您的组件创建 EventCallback“委托”时,编译器插入源代码中的代码会自动调用它。
触发 UI 事件后会自动调用 StateHasChanged 方法。
| 归档时间: |
|
| 查看次数: |
7470 次 |
| 最近记录: |