绑定属性不会在更改时更新

use*_*429 5 .net c# blazor

在我的 Blazor 应用程序中,我在视图中有以下输入字段:

<input bind="@amount.Display" type="text" />
Run Code Online (Sandbox Code Playgroud)

这绑定到使用以下访问器定义的属性:

get
{
    return _display;
}
set
{
    var parsed = Decimal.Parse(value);
    _display = parsed.ToString("F2");
}
Run Code Online (Sandbox Code Playgroud)

真正的访问器逻辑比这更复杂,但我在上面尽可能地简化了它,同时仍然保留了让我感到困惑的行为。

基本上,当用户输入“2”,然后标签或点击输入字段时,我希望它自动转换为“2.00”。奇怪的是,这种转换似乎只有在用户输入的字符串表示的数字与已经存在的数字不同时才会发生。例如,如果输入字段当前的值为“1.00”,而我输入“2”,则正确地以“2.00”结尾。但是,如果输入字段的值为“2.00”而我输入“2”,则它只是保持“2”。就好像在后一种情况下没有调用 set 访问器,我无法想象为什么。

Kir*_*oll 11

主要问题是,如果 Blazor 认为文本框的值没有更改,则不会更新文本框。2您的示例的部分问题是值(您的属性)的内部表示有时与您在文本框中看到的内容( vs. )不一致2.00。但就 Blazor 而言,如果属性值未更改,则不会将绑定传播回文本框。

我尝试了代码的许多变体(使用value和手动“绑定onchange”),但最终如果当您的代码完成更新 value 属性并且该值与之前相同时,什么都不会发生。

我能想到的唯一解决方法是通过使用 async 来引入一个非常丑陋的 hack。当您执行此操作时,事件循环在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

希望比我更了解 Blazor 的人可以提供一些不那么残暴的东西。但它确实有效。(顺便说一句,不起作用Task.Delay(0),可能是由于任务已经完成的一些优化,因此没有承诺退出事件循环。)

注意:
一旦 Blazor 格式字符串(即format-value="yyyy-MM-dd")接受数字,您可能可以通过仅将值存储为小数并直接在 razor 标记中使用格式字符串来简化此操作。

  • 根据您的描述,这听起来像是 Blazor 中的一个错误,因为它知道它调用了具有不同值的 setter,是的,之前是“2.00”,现在又是“2.00”——但是在这两个调用之间,它称为setter 的值为“2”,因为它绑定到一个属性 - 所以它确实发生了变化,它是“2.00”和“2”,现在它应该再次是“2.00”......但是因为 Blazor 忽略了setter 调用时,它被显示为“2”。这显然是错误的行为。 (3认同)

cod*_*ion 8

如果你想强制 UI 重新渲染,在 Blazor 中我建议你使用StateHasChanged()

get
{
    return _display;
}
set
{
    var parsed = Decimal.Parse(value);
    _display = parsed.ToString("F2");
    StateHasChanged();
}
Run Code Online (Sandbox Code Playgroud)

Blazor 不重新渲染的真正原因是:它试图保存重建 HTML。由于 Blazor 知道您将属性绑定到input它,因此相信在设置属性后无需触发重新渲染。

更新工作:

  1. 用户输入文本“5”并按 Tab 键
  2. Htmlonchange事件已生成
  3. Blazor 捕获事件onchange并调用amount.Display = "5";
  4. 完毕。

  • 我已经尝试过这个,但它不起作用。这个建议也无法解释我所描述的差异:为什么输入字段更新不一致? (3认同)