看起来可能很简单,但有几件事情需要考虑。
在Blazor中,从输入到模型的通道是通过事件处理的。如果您使用@bind-
语法,编译器会为您构建处理程序。因此,您不能(轻松地)同时更新模型值并执行另一个处理程序。
然而,有方便的方法可以实现您想要的效果。但它们有缺点。根据您的上下文,您需要决定什么是最好的。
使用不同的事件
@page "/DifferentEvents"
<input class="form-control form-control-sm" type="number" step="any"
@bind-value:event="onchange" @oninput="CalculateStandardDimensions" @bind-value="Cyclone.CycloneSize" />
@code
{
public class Cyclon
{
public Int32 CycloneSize { get; set; } = 10;
}
public Cyclon Cyclone = new Cyclon();
private void CalculateStandardDimensions(ChangeEventArgs args)
{
// Do Stuff Here
}
}
在这种情况下,当输入失去焦点(onchange)时,您的模型将进行更新,但是每次输入更改时,都会执行您的
CalculateStandardDimensions
方法。通过
ChangeEventArgs args
可以访问新值。
缺点:由于模型不知道更新,因此可能存在不一致性,但您仍可以使用它来做其他事情。
使用具有双向绑定的中介属性。
@page "/IntermediatePropertyWithBinding"
<input class="form-control form-control-sm" type="number" step="any" @bind-value:event="onInput" @bind-value="Size" />
@code
{
public class Cyclon
{
public Int32 CycloneSize { get; set; } = 10;
}
public Cyclon Cyclone = new Cyclon();
private Int32 _size;
public Int32 Size
{
get => _size;
set
{
_size = value;
CalculateStandardDimensions();
Cyclone.CycloneSize = value;
}
}
private void CalculateStandardDimensions()
{
}
}
通过引入字段_size
和属性Size
,您可以绑定并且Size
的setter将调用CalculateStandardDimensions()
。基于绑定事件onInput
或onChange
,您可以控制回写的时间。
您可以完全控制绑定,避免不一致。但是,您需要为每个希望具有此类型行为的属性完成此操作。
在没有绑定的情况下使用中介属性
@page "/IntermediatePropertyWithoutBinding"
<input class="form-control form-control-sm" type="number" step="any" value="@_size" @oninput="ValueChanged" />
@code
{
public class Cyclon
{
public Int32 CycloneSize { get; set; } = 10;
}
public Cyclon Cyclone = new Cyclon();
private Int32 _size;
private void ValueChanged(ChangeEventArgs args)
{
_size = Convert.ToInt32((String)args.Value);
Cyclone.CycloneSize = _size;
CalculateStandardDimensions();
}
private void CalculateStandardDimensions()
{
}
}
我们摆脱了绑定和属性。直接设置输入字段的值。(不使用@bind-value
) 在事件处理程序中,我们设置更新值,写回模型并执行CalculateStandardDimensions()
方法。
我们失去了双向绑定的所有功能,但不再需要属性。
EditContext OnFieldChanged事件
@page "/WithEditContext"
@implements IDisposable
<EditForm EditContext="_editContext">
<InputNumber class="form-control form-control-sm" type="number" step="any" @bind-Value:event="onchange" @bind-Value="Cyclone.CycloneSize" />
</EditForm>
@code
{
public class Cyclon
{
public Int32 CycloneSize { get; set; } = 10;
}
private EditContext _editContext;
public Cyclon Cyclone = new Cyclon();
protected override void OnInitialized()
{
base.OnInitialized();
_editContext = new EditContext(Cyclone);
_editContext.OnFieldChanged += OnFormUpdated;
}
public void Dispose()
{
_editContext.OnFieldChanged -= OnFormUpdated;
}
private void OnFormUpdated(Object sender, FieldChangedEventArgs args)
{
if(args.FieldIdentifier.FieldName == nameof(Cyclon.CycloneSize))
{
CalculateStandardDimensions();
}
}
private void CalculateStandardDimensions()
{
}
}
EditContext
在使用带有
Model
属性的
EditForm
时会隐式创建,并在将值写回到模型时触发事件。我们需要显式创建
EditContext
并订阅该事件来使用它。不要忘记稍后移除处理程序。这就是为什么我们实现了
IDisposable
。事件处理程序本身检查字段是否符合预期并执行方法
CalculateStandardDimensions()
。HTML 输入元素需要替换为
InputNumber
以使绑定工作。
这种方法具有非常高的灵活性,但也伴随着更多的复杂性。然而,您可以将其与任何输入组件一起使用,例如 InputText
或 InputSelect
。
<input ...
替换为<InputNumber class="form-control form-control-sm" type="number" step="any" @bind-Value:event="onchange" @bind-Value="Cyclone.CycloneSize" />
我已经更新了代码并添加了一个小的解释。 - Just the benno