是否期望从 InputNumber<T> 派生的自定义组件仅绑定单向?

Is it expected that a custom component derived from InputNumber<T> only binds one-way?

我创建了一个继承自 InputNumber 的简单自定义 Blazor 组件,以包含一个输入元素和一些其他便利设施(为简单起见,我在此处删除了额外内容)。

我遇到的问题是 属性 绑定只对组件有效。我有一个简单的演示,其中包含这个自定义组件和一个简单的输入元素,绑定到相同的 属性。当输入元素用于更改值时,这会在自定义组件中重复,但是当使用自定义组件时,更改永远不会返回到绑定 属性(或输入元素)。

经过大量挖掘,我提出了一个(对我而言)不令人满意的解决方案,其中涉及复制一些框架 classes(InputNumber 和 InputBase)并向值添加更改通知属性 setter in InputBase 如下:

以前的定义:

    [Parameter]
    public TValue? Value
    {
        get; set;
    }

修改后的定义:

    [Parameter]
    public TValue? Value
    {
        get { return _value; }
        set
        {
            if (EqualityComparer<TValue>.Default.Equals(_value, value)) return;

            _value = value;
            ValueChanged.InvokeAsync(value);
            var fieldIdentifier = FieldIdentifier.Create(ValueExpression);
            EditContext.NotifyFieldChanged(fieldIdentifier);
        }
    }
    private TValue? _value;

注意,大部分框架代码都被标记为内部代码,因此我实际上不得不 copy/paste 4 class 进入我的项目,如下所示,以便编译。

我不禁觉得我误解了一些基本的东西:我不明白为什么 InputNumber 默认情况下不参与更改通知。

我没听懂吗?

这是我的两个组件和测试页面:

InputNumberComponent.razor - 我的原始输入组件

仅绑定单向组件。

@inherits InputNumber<T>
@typeparam T

<input type="number" id="@Id" @bind-value="@Value" @bind-value:event="oninput" />

@code {
    [Parameter]
    public string? Id{ get; set; }
}

InputNumberHack.razor - 修改后的输入组件

双向绑定。 InputNumberCopy是修改后的框架class,依次继承自InputBaseCopy,也就是我修改的地方值 属性.

@inherits InputNumberCopy<T>
@typeparam T

<input type="number" id="@Id" @bind-value="@Value" @bind-value:event="oninput" />

@code {
    [Parameter]
    public string? Id{ get; set; }
}

InputTest.razor - 测试页。

@page "/"
@using BlazorBindingTest.Client.Components

<PageTitle>Input Test</PageTitle>

<EditForm Model="this">
    <h1>Pair 1 (only binds one-way to the component)</h1>

    <div>Simple input bound to local value 1</div>
    <input type="number" @bind-value="LocalValue1" @bind-value:event="oninput" />

    <div>Custom input bound to local value 1</div>
    <InputNumberComponent Id="lv" @bind-Value="LocalValue1" />


    <h1 class="mt-4">Pair 2 - hacked InputNumber base (binds two-way to the component)</h1>

    <div>Simple input bound to local value 2</div>
    <input type="number" @bind-value="LocalValue2" @bind-value:event="oninput" />

    <div>Custom input bound to local value 2</div>
    <InputNumberHack Id="lv" @bind-Value="LocalValue2" />
</EditForm>

@code {
    public decimal LocalValue1 { get; set; } = 0m;
    public decimal LocalValue2 { get; set; } = 0m;
}

您绑定到错误的 property/field。 Value 是一个组件 [Parameter],因此被正确处理为只读,这就是您所看到的。 CurrentValueAsString 是您需要使用的 read/write protected 字段。它连接到所有内部通知和验证过程中。

@inherits InputNumber<T>
@typeparam T

<input type="number" id="@Id" @bind-value="@CurrentValueAsString" @bind-value:event="oninput" />

@code {
    [Parameter]
    public string? Id{ get; set; }
}

如果你想看看发生了什么,这里是 InputNumber and the code for InputBase 的代码。