Blazor WASM UI 更新不一致
Blazor WASM UI updates inconsistent
我的应用程序中有一个简单的登录功能。登录开始时,布尔值设置为 true 以激活加载动画,完成后设置为 false 以隐藏它。问题是 UI 对第二部分没有反应,但对第一部分有反应。
这是函数:
private async void AttemptLogin()
{
//This updates
LoginInProgress = true;
try
{
var result = await _loginPageViewModel.Login(Username, Password, exception => { Console.WriteLine(exception.Message); }); //TODO add notifier
if (result)
{
Console.WriteLine("success");
_navigationManager.NavigateTo("./");
}
else
{
Console.WriteLine("Failure");
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
//This does not update
LoginInProgress = false;
}
Console.WriteLine("Login attempt finished");
}
我正在使用 blazorise 作为组件框架,这就是值的绑定方式(+ 一个额外的测试复选框,选中和取消选中会按预期更新所有内容):
<Button Clicked="AttemptLogin" @bind-Loading="LoginInProgress">Login</Button>
<Check TValue="bool" @bind-Checked="LoginInProgress">Test</Check>
目前,LoginInProgress = false;
处的 StateHasChanged 似乎有效,但我不喜欢我必须将它放在某些地方而不是其他地方。我做错了什么?
Blazor 将在组件中的任何事件处理程序完成后执行当前组件的内部“StateHasChanged”重新呈现。
因此,在正常情况下捕获“Clicked”事件并在“AttemptLogin”方法中处理它,然后 Blazor 引擎将在 AttemptLogin 完成后重新呈现并考虑变量“LoginInProgress = false”。无需手动调用“StateHasChanged.
但是,由于您的方法是异步的,因此引擎将等待完成。通常,您会 return 引擎将保留并等待该任务完成后再执行重新渲染的任务。
在你的例子中,你 return 是一个 void 而不是一个 Task。结果是,只要您的 AttempLogin 方法首先调用它 await,控制权就会 return 交给调用者(Blazor 引擎),它将认为该方法已完成。
var result = await _loginPageViewModel
.Login(Username, Password, exception =>
{ Console.WriteLine(exception.Message); });
如果您 return 编辑了一个任务,它会等到方法完成(结果由任务提供),但是因为您 return 一个空的,那么引擎期望该方法没有进一步的响应并立即开始重新渲染。此重新渲染将在执行此行之前发生:
LoginInProgress = false;
因此,将在 LoginInProgress 仍然为真时应用重新呈现。
将您的 return 类型更改为任务,重新呈现将延迟到事件处理程序完成。
我的应用程序中有一个简单的登录功能。登录开始时,布尔值设置为 true 以激活加载动画,完成后设置为 false 以隐藏它。问题是 UI 对第二部分没有反应,但对第一部分有反应。
这是函数:
private async void AttemptLogin()
{
//This updates
LoginInProgress = true;
try
{
var result = await _loginPageViewModel.Login(Username, Password, exception => { Console.WriteLine(exception.Message); }); //TODO add notifier
if (result)
{
Console.WriteLine("success");
_navigationManager.NavigateTo("./");
}
else
{
Console.WriteLine("Failure");
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
//This does not update
LoginInProgress = false;
}
Console.WriteLine("Login attempt finished");
}
我正在使用 blazorise 作为组件框架,这就是值的绑定方式(+ 一个额外的测试复选框,选中和取消选中会按预期更新所有内容):
<Button Clicked="AttemptLogin" @bind-Loading="LoginInProgress">Login</Button>
<Check TValue="bool" @bind-Checked="LoginInProgress">Test</Check>
目前,LoginInProgress = false;
处的 StateHasChanged 似乎有效,但我不喜欢我必须将它放在某些地方而不是其他地方。我做错了什么?
Blazor 将在组件中的任何事件处理程序完成后执行当前组件的内部“StateHasChanged”重新呈现。
因此,在正常情况下捕获“Clicked”事件并在“AttemptLogin”方法中处理它,然后 Blazor 引擎将在 AttemptLogin 完成后重新呈现并考虑变量“LoginInProgress = false”。无需手动调用“StateHasChanged.
但是,由于您的方法是异步的,因此引擎将等待完成。通常,您会 return 引擎将保留并等待该任务完成后再执行重新渲染的任务。
在你的例子中,你 return 是一个 void 而不是一个 Task。结果是,只要您的 AttempLogin 方法首先调用它 await,控制权就会 return 交给调用者(Blazor 引擎),它将认为该方法已完成。
var result = await _loginPageViewModel
.Login(Username, Password, exception =>
{ Console.WriteLine(exception.Message); });
如果您 return 编辑了一个任务,它会等到方法完成(结果由任务提供),但是因为您 return 一个空的,那么引擎期望该方法没有进一步的响应并立即开始重新渲染。此重新渲染将在执行此行之前发生:
LoginInProgress = false;
因此,将在 LoginInProgress 仍然为真时应用重新呈现。
将您的 return 类型更改为任务,重新呈现将延迟到事件处理程序完成。