Blazor的OnChange事件

18

我想在值绑定后也触发方法CalculateStandardDimensions。我尝试了一些不同的语法组合,但仍然缺少一些东西使其正常工作。 离开输入不会执行该方法。

当值更改时,如何绑定该值并调用方法?

<input class="form-control form-control-sm" type="number" step="any" @bind-value:event="onchange=CalculateStandardDimensions()" @bind-value="Cyclone.CycloneSize" />

我在代码部分有这个。

    private void CalculateStandardDimensions()
    {
        // Do Stuff Here
    }
1个回答

35

看起来可能很简单,但有几件事情需要考虑。

在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()
    {
        // Do Stuff Here
    }
}

通过引入字段_size和属性Size,您可以绑定并且Size的setter将调用CalculateStandardDimensions()。基于绑定事件onInputonChange,您可以控制回写的时间。

您可以完全控制绑定,避免不一致。但是,您需要为每个希望具有此类型行为的属性完成此操作。

在没有绑定的情况下使用中介属性

@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()
    {
        // Do Stuff Here
    }
}

我们摆脱了绑定和属性。直接设置输入字段的值。(不使用@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 以使绑定工作。

这种方法具有非常高的灵活性,但也伴随着更多的复杂性。然而,您可以将其与任何输入组件一起使用,例如 InputTextInputSelect


我尝试了EditContext选项的代码,但当值改变时事件没有触发。我从模板创建了一个新的Blazor Server应用程序,然后添加了上面的代码,但OnFormUpdated没有被触发。我正在更深入地研究这个选项,因为我猜测这是一些小问题。 - Kris Hahn
一个小的复制粘贴错误将<input ...替换为<InputNumber class="form-control form-control-sm" type="number" step="any" @bind-Value:event="onchange" @bind-Value="Cyclone.CycloneSize" />我已经更新了代码并添加了一个小的解释。 - Just the benno
非常感谢您的帮助。我刚刚弄清楚了这个问题,并准备回来发布我找到的内容。我需要更多地了解为什么绑定会以这种方式工作。再次感谢! - Kris Hahn
非常棒的答案,非常感谢。 - Sire
这是我在SO上见过的最好的回答之一。赞! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接