假设我要使用EditForm,但我希望每次用户在控件中键入值时触发值绑定,而不是仅在模糊时触发。举例来说,假设我想要一个做到这一点的InputNumber?我尝试使用不同的方式浮动,例如bind-Value:event =“ oninput”,但没有成功。通过复制InputNumber的AspNetCore源代码并覆盖/重写一些东西,我终于能够或多或少地获得所需的东西。这是我的InputNumber,可以实现我所希望的:
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;
}
}
请注意,序列6项中的“ oninput”已从基本InputNumber的BuildRenderTree方法中的“ onchange”更改为。我想知道如何a)看到BuildRenderTree的输出,以便我可以知道如何使用Razor和/或b)大致上知道哪种剃刀语法等效于在未来。我从AspNetCore代码中的注释中收集到,这绝对不是执行此操作的首选方法,而Razor是首选方法。我已经通过订阅EditContext的OnFieldChangedEvent来测试了在.NET Core 3 Preview 7 Asp.net Core托管Blazor中的工作原理,并且可以看到通过这种方法,我得到了所寻找的不同行为。希望有更好的方法。
更新:包括有关该问题的更多信息
@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}");
}
}
}
我要寻找的是当我在输入中键入内容时触发的“ EditContext_OnFieldChanged”事件。当前示例有效,只是在寻找更好的方法。
答案 0 :(得分:5)
对于任何想知道的人,您都可以将InputText子类化以更改其呈现方式。例如,要使其使用oninput事件,请创建包含以下内容的MyInputText.razor:
@inherits Microsoft.AspNetCore.Components.Forms.InputText
<input @attributes="@AdditionalAttributes" class="@CssClass" @bind="@CurrentValueAsString" @bind:event="oninput" />
现在,当您使用<MyInputText @bind-Value="@someval" />
时,它的行为就像InputText一样,只是它会在每次击键时更新。
SteveSanderson
答案 1 :(得分:3)
从组件继承并对其进行更改,以使其响应input
事件已在official documentation for .NET Core 3.1中涵盖:
基于输入事件的InputText
使用
InputText
组件创建一个使用input
事件而不是change
事件的自定义组件。使用以下标记创建一个组件,并像使用
InputText
一样使用该组件:剃刀:
@inherits InputText <input @attributes="AdditionalAttributes" class="@CssClass" value="@CurrentValue" @oninput="EventCallback.Factory.CreateBinder<string>( this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />
该文档还提供了an example of how to inherit a generic component:
@using System.Globalization @typeparam TValue @inherits InputBase<TValue>
因此,如果您随后将两者结合在一起,则可以创建一个更改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)" />
包含type="number"
部分将具有与现有InputNumber
相同的行为(仅允许输入数字字符,使用向上和向下箭头递增/递减等)
如果将上面的代码放在Blazor项目的Shared文件夹中名为InputNumberUpdateOnInput.razor的文件中,则可以使用与使用常规InputNumber
相同的方式来使用组件,例如:
<InputNumberUpdateOnInput class="form-control text-right" @bind-Value="@invoiceLine.Qty" />
如果要控制小数位数,则组件将允许您将step
值设为传递给组件的参数。 step
in this answer上有更多内容。
答案 2 :(得分:1)
尝试一下:
v.12.4.0
更多...
不建议您使用此方法。您应该使用Razor对组件进行子类化。
下面是一个应该工作的示例。它可以重定向您如何获得解决方案。
包装InputText的解决方案:
<input type="text" id="example1" @bind-value="@value" @bind-value:event="oninput" />
<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; }
}
您也可以像这样直接从InputBase继承:
<span>Name of the category: @category.Name</span>
<EditForm Model="@category">
<NewInputText @bind-Value="@category.Name"/>
</EditForm>
希望这对您有帮助...
答案 3 :(得分:1)
好吧,我在仔细研究了源代码之后,特别是在查看了属性CurrentValueAsString和CurrentValue之后,已经弄清楚了。这是我提出的一种解决方案,用于使文本输入正确触发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" />
如果这是开箱即用的输入组件上易于配置的选项,那将非常好,但是至少有一种方法可以使我的皮肤不会爬行。
答案 4 :(得分:0)
我发现如果他/她避免使用@bind 而是像这样手动绑定,他/她可以做到这一点:
<InputText Value=@MyValue @oninput=@HandleInputChange ValueExpression=@(() => MyValue) />
@{
// This will change for every character which is entered/removed from the input
Public string MyValue { get; set; }
void HandleInputChange(ChangeEventArgs args)
{
MyValue = args.Value.ToString();
}
}
我仍然不明白为什么会这样。我认为这是因为 AdditionalAttributes 参数。它将 oninput 属性传递给更新您的值的 html <input>
元素,因此您不再依赖 ValueChanged 回调来更新您的值。