在我的 Blazor 应用中,我在视图中有以下输入字段:
<input bind="@amount.Display" type="text" />
这绑定到使用以下访问器定义的属性:
get
{
return _display;
}
set
{
var parsed = Decimal.Parse(value);
_display = parsed.ToString("F2");
}
真正的访问器逻辑比这更复杂,但我在上面尽可能地简化了它,同时仍然保留让我感到困惑的行为。
基本上,当用户输入"2",然后按 Tab 键或单击输入字段时,我希望它自动转换为"2.00"。奇怪的是,这种转换似乎只有在用户输入一个表示与现有数字不同的字符串时才会发生。例如,如果输入字段当前具有"1.00"的值,而我输入"2",则我正确地以"2.00"结尾。但是,如果输入字段的值为"2.00",而我输入"2",则它仅保持"2"。就好像在后一种情况下没有调用 set 访问器一样,我无法想象为什么。
主要问题是,如果 Blazor 认为其值未更改,则它不会更新文本框。 您的示例的部分问题是,值(您的属性(的内部表示有时与您在文本框中看到的内容不一致(2
vs.2.00
(。 但就 Blazor 而言,如果属性值未更改,则不会将绑定传播回文本框。
我尝试了代码的许多变体(使用value
和onchange
手动"绑定"(,但最终,如果您的代码完成更新 value 属性并且值与以前相同,则不会发生任何事情。
我能想到的唯一解决方法是使用异步引入一个非常丑陋的黑客。执行此操作时,事件循环将在await
后完成(blazor 将接受新值2
(,并且 blazor 将在恢复await
调用时再次检查是否有任何更改,因为此时它是新一轮的事件循环。 由于新值现在将2.00
而不是2
因此它将刷新文本框。
@functions {
private string value;
private string Value
{
get => value;
set => SetValue(value);
}
private async void SetValue(string value)
{
this.value = value;
await Task.Delay(1);
this.value = decimal.Parse(value).ToString("F2");
StateHasChanged();
}
}
希望比我更了解 Blazor 的人可以提供一些不那么残暴的东西。但它确实有效。 (顺便说一句,Task.Delay(0)
不起作用,大概是由于一些优化,其中任务已经完成,因此没有获得退出事件循环的承诺。
注意:
一旦 Blazor 格式字符串(即format-value="yyyy-MM-dd"
( 接受数字,您可能可以通过将值存储为小数并直接在 razor 标记中使用格式字符串来简化此操作。
如果要强制 UI 重新呈现,建议在 Blazor 中使用StateHasChanged()
get
{
return _display;
}
set
{
var parsed = Decimal.Parse(value);
_display = parsed.ToString("F2");
StateHasChanged();
}
Blazor 不重新呈现的真正原因是:它试图保存重建 HTML。由于 Blazor 知道已将属性绑定到input
因此它认为在设置属性后无需触发重新呈现。
更新工作:
- 用户输入文本"5",然后按 Tab 键
- 生成 HTML
onchange
事件 - Blazor甚至捕获
onchange
并呼叫amount.Display = "5";
- 做。