当我在HTML元素上有一个单向绑定,并且在onchange
上附带的绑定并不总是改变它,那么我如何告诉或允许Blazor"刷新";元素的值从它的绑定值开始没有改变?
StateHasChanged()不起作用,可能是因为Blazor检测到没有更改。
极简但荒谬的例子(注意现实世界的情况并不荒谬):
@page "/"
<select value="@Foo" @onchange="Update">
<option>First</option>
<option>Second</option>
</select>
<div>
Value of Foo: @Foo
</div>
@code {
private string Foo {get;set;} = "First";
private void Update(ChangeEventArgs args) {
return; // doesn't actually change it
}
}
因此,HTML元素中的新值在更改时立即显示,但绑定的值实际上永远不会更改。这里的工作演示:我如何获得下拉列表的值保持(或更改回)"First",这是存储在Foo中的未更改的值?
最简单的方法是给元素一个@key
,当您想要强制刷新时更改它。但是,这将完全破坏并重新创建元素,因此它可能是昂贵的。
@page "/"
<select @key="@Forced" value="@Foo" @onchange=@( e => Update(e) )>
<option>(none)</option>
<option>First</option>
<option>Second</option>
</select>
@code {
private string Foo {get;set;} = "First";
private int Forced {get;set;} = 0;
private Task Update(ChangeEventArgs args) {
if (1 == 1){ // placeholder for other logic
Forced++; // doesn't actually change it
}
else
{
Foo = args.Value.ToString() ?? "(none)";
}
return Task.CompletedTask;
}
}
更新演示问题在于Renderer和Diffing引擎。
该值在浏览器DOM中改变了,但在渲染器DOM中没有改变。这是两人"合法"得到的为数不多的场合之一。在Blazor中不同步。因此,当您将值更改回原来的值时,Diffing引擎看不到任何差异,因此不会向浏览器DOM发送任何更新。在构建只允许某些输入字符的文本框时,您会看到类似的情况。
我知道的唯一解决方案是利用Blazor UI事件处理程序的异步行为。
- 将值设置为不同的值-我通常使用
String.Empty
2。生成控制,以便UI可以使用Task.Delay
进行更新 - UI处理器调用
StateHasChanged
并更新UI。 - 设置为你想要的值
- UI处理程序执行最终的
StateHasChanged
并将输入更新为正确的值。
@page "/"
<div>
Foo: <select value="@Foo" @onchange="Update">
<option>(none)</option>
<option>First</option>
<option>Second</option>
</select>
</div>
<div>
Value of Foo: @Foo
</div>
@code {
private string Foo {get;set;} = "First";
private async Task Update(ChangeEventArgs args) {
Foo = string.Empty;
await Task.Delay(1);
Foo = "First";
}
}
如果我理解你的要求,试试这段代码,它将显示Foo
的选定值<select value="@Foo" @onchange="@(e=> Foo=e?.Value?.ToString())">
<option value="(none)">(none)</option>
<option value="First">First</option>
<option value="Second">Second</option>
</select>