如何制作使用 oninput 而不是 onchange 绑定的 EditForm Input?

Jak*_*ows 8 .net c# asp.net-core blazor

假设我想使用EditForm,但我希望值绑定在每次用户输入控件时触发,而不是仅仅在模糊时触发。

举个例子,假设我想要一个InputNumber<int>这样做的?我试过使用不同的方法,但bind-Value:event="oninput"没有成功。通过复制 AspNetCore 源代码InputNumber并覆盖/重写一些东西,我终于能够或多或少地获得我想要的东西。

这是我的InputNumber<int>,它实现了我所希望的:

    public class MyInputNumber: InputNumber<int>
    {
        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.OpenElement(0, "input");
            builder.AddAttribute(1, "step", "any");
            builder.AddMultipleAttributes(2, AdditionalAttributes);
            builder.AddAttribute(3, "type", "number");
            builder.AddAttribute(4, "class", CssClass);
            builder.AddAttribute(5, "value", FormatValue(CurrentValueAsString));
            builder.AddAttribute(6, "oninput", EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString));
            builder.CloseElement();
        }

        // Copied from AspNetCore - src/Components/Components/src/BindConverter.cs
        private static string FormatValue(string value, CultureInfo culture = null) => FormatStringValueCore(value, culture);
        // Copied from AspNetCore - src/Components/Components/src/BindConverter.cs
        private static string FormatStringValueCore(string value, CultureInfo culture)
        {
            return value;
        }
    }
Run Code Online (Sandbox Code Playgroud)

注意“ oninput”中的序列6项被从“ onchange”中的碱InputNumberBuildRenderTree方法。我想知道如何:

  1. 查看 的输出BuildRenderTree,以便我知道如何使用 Razor 和/或
  2. 只是大致知道什么样的 Razor 语法相当于将来这样做。

我从 AspNetCore 代码中的评论中收集到,这绝对不是做这类事情的首选方法,而 Razor 是首选方法。我已经通过订阅EditContext's测试了这在 .NET Core 3 Preview 7 ASP.NET Core Hosted Blazor 中是否有效OnFieldChangedEvent,并且可以看到通过这种方法我得到了我正在寻找的不同行为。希望有更好的方法。

更新

包括有关问题的更多信息

@using BlazorAugust2019.Client.Components;
@inherits BlazorFormsCode
@page "/blazorforms"

<EditForm EditContext="EditContext">
    <div class="form-group row">
        <label for="date" class="col-sm-2 col-form-label text-sm-right">Date: </label>
        <div class="col-sm-4">
            <KlaInputDate Id="date" Class="form-control" @bind-Value="Model.Date"></KlaInputDate>
        </div>
    </div>
    <div class="form-group row">
        <label for="summary" class="col-sm-2 col-form-label text-sm-right">Summary: </label>
        <div class="col-sm-4">
            <KlaInputText Id="summary" Class="form-control" @bind-Value="Model.Summary"></KlaInputText>
        </div>
    </div>
    <div class="form-group row">
        <label for="temperaturec" class="col-sm-2 col-form-label text-sm-right">Temperature &deg;C</label>
        <div class="col-sm-4">
            <KlaInputNumber Id="temperaturec" Class="form-control" @bind-Value="Model.TemperatureC"></KlaInputNumber>
        </div>
    </div>
    <div class="form-group row">
        <label for="temperaturef" class="col-sm-2 col-form-label text-sm-right">Temperature &deg;F</label>
        <div class="col-sm-4">
            <input type="text" id="temperaturef" class="form-control" value="@Model.TemperatureF" readonly />
        </div>
    </div>
</EditForm>
Run Code Online (Sandbox Code Playgroud)
using BlazorAugust2019.Shared;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using System;

namespace BlazorAugust2019.Client.Pages.BlazorForms
{
    public class BlazorFormsCode : ComponentBase
    {
        public EditContext EditContext;
        public WeatherForecast Model;

        public BlazorFormsCode()
        {
            Model = new WeatherForecast()
            {
                Date = DateTime.Now,
                Summary = "Test",
                TemperatureC = 21
            };
            EditContext = new EditContext(Model);
            EditContext.OnFieldChanged += EditContext_OnFieldChanged;
        }

        private void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
        {
            Console.WriteLine($"EditContext_OnFieldChanged - {e.FieldIdentifier.FieldName}");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是EditContext_OnFieldChanged当我输入输入时要触发的“ ”事件。当前示例有效,只是寻找更好的方法。

Isa*_*aac 20

对于任何想知道的人,您可以创建子类InputText以更改它的呈现方式。例如,要使其使用该oninput事件,请创建包含以下内容的MyInputText.razor

@inherits Microsoft.AspNetCore.Components.Forms.InputText
<input @attributes="@AdditionalAttributes" class="@CssClass" @bind="@CurrentValueAsString" @bind:event="oninput" />
Run Code Online (Sandbox Code Playgroud)

现在,当您使用<MyInputText @bind-Value="@someval" />它时,它的行为就像是InputText在每次击键时更新。

史蒂夫·桑德森

  • 另外,尚不清楚从 `InputText` 继承有什么好处,而我可以使用纯 html 输入来达到相同的效果。 (2认同)

tom*_*dox 6

.NET Core 3.1input官方文档现在介绍了从组件继承并更改它以响应事件:

基于输入事件的 InputText

使用InputText组件创建使用input事件而不是事件的自定义组件change

使用以下标记创建一个组件,并按原样使用该组件InputText

剃刀:

@inherits InputText

<input
    @attributes="AdditionalAttributes" 
    class="@CssClass" 
    value="@CurrentValue" 
    @oninput="EventCallback.Factory.CreateBinder<string>(
        this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />
Run Code Online (Sandbox Code Playgroud)

该文档还提供了如何继承通用组件的示例

@using System.Globalization
@typeparam TValue
@inherits InputBase<TValue>
Run Code Online (Sandbox Code Playgroud)

因此,如果您将这两者结合在一起,您可以创建一个组件来更改组件的行为,InputNumber如下所示:

@typeparam TNumber
@inherits InputNumber<TNumber>

<input 
   type="number"
   step="any"
   @attributes="AdditionalAttributes" 
   class="@CssClass" 
   value="@CurrentValue" 
   @oninput="EventCallback.Factory.CreateBinder<string>(
        this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />
Run Code Online (Sandbox Code Playgroud)

包含该type="number"部分将提供与现有相同的行为InputNumber(仅允许输入数字字符,使用向上和向下箭头增加/减少等)

如果您将上面的代码放在 Blazor 项目的 Shared 文件夹中名为 say InputNumberUpdateOnInput.razor 的文件中,则可以像使用普通 一样使用该组件InputNumber,例如:

<InputNumberUpdateOnInput class="form-control text-right" @bind-Value="@invoiceLine.Qty" />
Run Code Online (Sandbox Code Playgroud)

如果要控制组件允许的小数位数,则需要将该step值设为传递给组件的参数。step 这个答案中有更多内容。