问题
Suppose I want to use an EditForm, but I want the value binding to trigger every time the user types into the control instead of just on blur. Suppose, for the sake of an example, that I want an InputNumber that does this? I've tried using different means that are floating around such as bind-Value:event="oninput" with no success. I was finally able to get more or less what I wanted by copying the AspNetCore source code for InputNumber and overriding / rewriting a few things. Here is my InputNumber which accomplishes what I'm hoping for:
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;
}
}
note the "oninput" in the sequence 6 item was changed from "onchange" in the base InputNumber's BuildRenderTree method. I'd like to know how to a) see the output of BuildRenderTree, so that I can know how to do this with Razor and/or b) just kind of know in general what sort of razor syntax would be equivalent to doing this in the future. I've gathered from comments in the AspNetCore code that this is definitely not the preferred way of doing this sort of thing, with Razor being the preferred approach. I've tested that this works in .NET Core 3 Preview 7 Asp.net Core Hosted Blazor by subscribing to the EditContext's OnFieldChangedEvent, and can see that with this approach I get the different behavior that I'm looking for. Hopefully there is a better way.
Update: Including some more information about the problem
@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 °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 °F</label>
<div class="col-sm-4">
<input type="text" id="temperaturef" class="form-control" value="@Model.TemperatureF" readonly />
</div>
</div>
</EditForm>
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}");
}
}
}
What I'm looking for is the "EditContext_OnFieldChanged" event to fire when I type into the inputs. The current example works, just looking for a better way.
回答1:
For anyone wondering, you can subclass InputText to change how it renders. For example, to make it use the oninput event, create MyInputText.razor containing:
@inherits Microsoft.AspNetCore.Components.Forms.InputText
<input @attributes="@AdditionalAttributes" class="@CssClass" @bind="@CurrentValueAsString" @bind:event="oninput" />
Now when you use <MyInputText @bind-Value="@someval" />
it will behave just like InputText except it updates on each keystroke.
SteveSanderson
回答2:
Try this:
<input type="text" id="example1" @bind-value="@value" @bind-value:event="oninput" />
More...
Your approach is not recommended. You should subclass your components using Razor.
The following is a sample that should work. It can redirects you how to get a solution.
A solution to wrap an InputText:
NewInputText.razor
<div class="form-group">
<label class="col-form-label">@Label</label>
<InputText Class="form-control" Value="@Value" ValueChanged="@ValueChanged" ValueExpression="@ValueExpression"></InputText>
</div>
@functions{
[Parameter] string Label { get; set; }
[Parameter] string Value { get; set; }
[Parameter] EventCallback<string> ValueChanged { get; set; }
[Parameter] Expression<Func<string>> ValueExpression { get; set; }
}
Index.razor
<span>Name of the category: @category.Name</span>
<EditForm Model="@category">
<NewInputText @bind-Value="@category.Name"/>
</EditForm>
You may also inherit from InputBase directly like so:
@inherits InputBase<string>
<input type="number" bind="@CurrentValue" id="@Id" class="@CssClass" />
Hope this helps...
回答3:
Alright, I've figured this out after poking around the source code looking particularly at properties CurrentValueAsString and CurrentValue. This is the solution I've come up with for making a text input that properly fires field changed events oninput:
public class InputTextCode : InputBase<string>
{
protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
{
result = value;
validationErrorMessage = null;
return true;
}
}
@inherits InputTextCode;
<input type="text" id="@Id" class="@Class" @bind-value="CurrentValueAsString" @bind-value:event="oninput" />
it would be really nice if this could be an easily configurable option on Input components out of the box, but at least there is a way to do it that doesn't make my skin crawl.
来源:https://stackoverflow.com/questions/57234446/how-to-make-an-editform-input-that-binds-using-oninput-rather-than-onchange