Я пытаюсь создать «составной» компонент ввода текста Blazor.
Я хотел бы объединить
Пока что я создал что-то вроде этого (немного упрощенно):
MyInputText.razor
:
<div class = "row">
<div class = "col-md-3">
<label>@Title</label>
</div>
<div class = "col-md-8">
<InputText class = "form-control" name = "textbox" @bind-Value = "Value" @oninput = "TextInputEvent" />
<ValidationMessage For = "() => Value" />
</div>
<div class = "col-md-1">
<label>@CurrentChars / @MaxChars</label>
</div>
</div>
MyInputText.razor.cs
:
public partial class MyTextInput
{
[Parameter]
[EditorRequired]
public string Title { get; set; } = string.Empty;
[Parameter]
[EditorRequired]
public string Value { get; set; } = string.Empty;
[Parameter]
[EditorRequired]
public int MaxChars { get; set; } = 255;
public int CurrentChars { get; set; }
private void TextInputEvent()
{
CurrentChars = Value.Length;
}
}
Кажется, почти работает, но:
Кажется, он всегда «на шаг позади» — поэтому, если у меня четыре символа и я ввожу пятый — для «CurrentChars» установлено значение 4. Кажется, он смотрит на «старое» содержимое Value
— перед символом, который я только что набрал зарегистрирован
Кажется, это работает только для первого символа, который я набираю - любые последующие символы, похоже, больше не запускают обработчик TextInputEvent
...
Есть идеи, чего мне здесь не хватает?
Это потому, что bind-value
обновляет значение после срабатывания on-input
. Пробовали ли вы сделать это одновременно:
<div class = "row">
<div class = "col-md-3">
<label>@Title</label>
</div>
<div class = "col-md-8">
<InputText class = "form-control" name = "textbox" value = "@Value" ValueChanged = "OnValueChanged" ValueExpression = "() => Value" />
<ValidationMessage For = "() => Value" />
</div>
<div class = "col-md-1">
<label>@CurrentChars / @MaxChars</label>
</div>
</div>
public partial class MyTextInput : ComponentBase
{
[Parameter]
[EditorRequired]
public string Title { get; set; } = string.Empty;
[Parameter]
[EditorRequired]
public string Value { get; set; } = string.Empty;
[Parameter]
[EditorRequired]
public int MaxChars { get; set; } = 255;
public int CurrentChars { get; set; }
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
private async Task OnValueChanged(ChangeEventArgs e)
{
Value = e.Value?.ToString() ?? string.Empty;
CurrentChars = Value.Length;
await ValueChanged.InvokeAsync(Value);
}
}
Я думаю, что значение связывается только после того, как ввод потерял фокус. Вам не нужны другие изменения. просто используйте:
private void TextInputEvent(ChangeEventArgs args)
{
CurrentChars = args.Value.ToString().Length;
}
Да, спасибо - работает как шарм!
Решает ли это фундаментальную проблему привязки - @bind-Value = "Value"
? Внутри компонента это установка параметра, которую не следует делать. Как обновляется модель родительской формы? См. — Learn.microsoft.com/en-us/aspnet/core/blazor/comComponents/…
Другие ответы касаются необходимости ручной привязки в вашем решении.
Альтернативой является наследование напрямую от InputText
.
Ключевым преимуществом этого является то, что вам не нужно изобретать велосипед. Вы используете все встроенные функции InputBase
с помощью EditContext
и проверки.
В примере я добавил опцию UpdateOnInput
, так как вы, вероятно, в какой-то момент воспользуетесь ею.
@inherits InputText
<div class = "row">
<div class = "col-md-3">
<label>@Title</label>
</div>
<div class = "col-md-8">
<input class = "@this.CssClass"
type = "text"
value = "@this.CurrentValueAsString"
@oninput = "this.OnInput"
@onchange = "this.OnChange"
@attributes=this.AdditionalAttributes
@ref=this.Element />
<ValidationMessage For = "() => Value" />
</div>
<div class = "col-md-1">
<label>@CurrentChars / @MaxChars</label>
</div>
</div>
@code {
[Parameter, EditorRequired] public string Title { get; set; } = string.Empty;
[Parameter, EditorRequired] public int MaxChars { get; set; } = 255;
[Parameter] public bool UpdateOnInput { get; set; }
public int CurrentChars { get; set; }
private void OnInput(ChangeEventArgs e)
{
CurrentChars = e?.Value?.ToString()?.Length ?? 0;
if (UpdateOnInput)
CurrentValueAsString = e?.Value?.ToString() ?? null;
}
private void OnChange(ChangeEventArgs e)
{
if (!UpdateOnInput)
CurrentValueAsString = e?.Value?.ToString() ?? null;
}
}
Демо:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<EditForm Model = "_model">
<MyInputText class = "form-control" @bind-Value = "_model.Value" MaxChars = "10" Title = "My Value" />
<MyInputText class = "form-control" @bind-Value = "_model.Value2" UpdateOnInput MaxChars = "10" Title = "My Value" />
</EditForm>
<div class = "bg-dark text-white m-2 p-2">
<pre>Value: @_model.Value</pre>
<pre>Value2: @_model.Value2</pre>
</div>
@code{
private Model _model = new();
public class Model
{
public string? Value { get; set; }
public string? Value2 { get; set; }
}
}
Хорошо, хорошая попытка, спасибо.
исправили это. пожалуйста, посмотрите.