是否期望从 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 的代码。
我创建了一个继承自 InputNumber
我遇到的问题是 属性 绑定只对组件有效。我有一个简单的演示,其中包含这个自定义组件和一个简单的输入元素,绑定到相同的 属性。当输入元素用于更改值时,这会在自定义组件中重复,但是当使用自定义组件时,更改永远不会返回到绑定 属性(或输入元素)。
经过大量挖掘,我提出了一个(对我而言)不令人满意的解决方案,其中涉及复制一些框架 classes(InputNumber
以前的定义:
[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
@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 的代码。