компоненты ввода ASP.NET Core Blazor

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

В этой статье описываются Blazorвстроенные входные компоненты.

Входные компоненты

Платформа Blazor предоставляет встроенные компоненты ввода для получения и проверки данных, введенных пользователем. Встроенные входные компоненты в следующей таблице поддерживаются в объекте EditFormEditContext.

Компоненты в таблице также поддерживаются вне формы в Razor разметке компонента. Входные данные проверяются при их изменении и отправке формы.

Компонент ввода Отображается как…
InputCheckbox <input type="checkbox">
InputDate<TValue> <input type="date">
InputFile <input type="file">
InputNumber<TValue> <input type="number">
InputRadio<TValue> <input type="radio">
InputRadioGroup<TValue> Группа дочернего элемента InputRadio<TValue>
InputSelect<TValue> <select>
InputText <input>
InputTextArea <textarea>

Дополнительные сведения о компоненте InputFile см. в статье Отправка файлов в ASP.NET Core Blazor.

Компонент ввода Отображается как…
InputCheckbox <input type="checkbox">
InputDate<TValue> <input type="date">
InputNumber<TValue> <input type="number">
InputSelect<TValue> <select>
InputText <input>
InputTextArea <textarea>

Примечание.

Компоненты InputRadio<TValue> и InputRadioGroup<TValue> доступны в ASP.NET Core 5.0 и более поздних версий. Для получения дополнительных сведений выберите вариант этой статьи для версии 5.0 или более поздней.

Все компоненты ввода, включая EditForm, поддерживают произвольные атрибуты. В отрисованный HTML-элемент добавляется любой атрибут, который не соответствует параметру компонента.

Компоненты ввода обеспечивают поведение по умолчанию для проверки при изменении поля:

  • Для входных компонентов в форме с EditContextтипом , поведение проверки по умолчанию включает обновление класса CSS поля, чтобы отразить состояние поля как допустимое или недопустимое с стили проверки базового HTML-элемента.
  • Для элементов управления без EditContext проверка по умолчанию предполагает отображение допустимого или недопустимого состояния, но не применяет проверочный стиль к основному HTML-элементу.

Некоторые компоненты включают в себя полезную логику синтаксического анализа. Например, InputDate<TValue> и InputNumber<TValue> обрабатывают не анализируемые значения надлежащим образом, регистрируя их как ошибки проверки. Типы, которые могут принимать значения NULL, также поддерживают допустимость значений NULL для целевого поля (например, int? для целого числа, допускающего значение NULL).

Дополнительные сведения о компоненте InputFile см. в статье Отправка файлов в ASP.NET Core Blazor.

Пример формы

Starship Следующий тип, который используется в нескольких примерах и примерах этой статьи в других статьях узлов Forms, определяет разнообразный набор свойств с заметками данных:

  • Id является обязательным, так как у него есть заметка RequiredAttribute. Для Id требуется использовать от одного до 16 символов. Это требование указано с помощью StringLengthAttribute.
  • Description является необязательным, так как у него нет заметки RequiredAttribute.
  • Classification является обязательным.
  • Свойству MaximumAccommodation по умолчанию присвоено значение 0, но оно должно быть от 1 до 100 000 согласно RangeAttribute.
  • IsValidatedDesign требует, чтобы у свойства было значение true, которое соответствует выбранному состоянию, когда свойство привязано к флажку в пользовательском интерфейсе (<input type="checkbox">).
  • ProductionDate — это DateTime и является обязательным.

Starship.cs:

using System.ComponentModel.DataAnnotations;

namespace BlazorSample;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string? Id { get; set; }

    public string? Description { get; set; }

    [Required]
    public string? Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", ErrorMessage = "Approval required.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string? Id { get; set; }

    public string? Description { get; set; }

    [Required]
    public string? Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string? Id { get; set; }

    public string? Description { get; set; }

    [Required]
    public string? Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string Id { get; set; }

    public string Description { get; set; }

    [Required]
    public string Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string Id { get; set; }

    public string Description { get; set; }

    [Required]
    public string Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}

Следующая форма принимает и проверяет данные, введенные пользователем, с помощью:

  • свойств и правил проверки, заданных в предыдущей модели Starship;
  • Несколько встроенных Blazorвходных компонентов.

Если задано свойство модели для классификации корабля (Classification), параметр, соответствующий модели, проверка. Например, checked="@(Model!.Classification == "Exploration")" для классификации судна разведки. Причина явного задания проверка заданного <select> параметра заключается в том, что значение элемента присутствует только в браузере. Если форма отрисовывается на сервере после отправки, любое состояние клиента переопределяется с состоянием с сервера, которое обычно не помечает параметр как проверка. Задав параметр проверка из свойства модели, классификация всегда отражает состояние модели. Это сохраняет выбор классификации между отправками форм, которые приводят к перерисовке формы на сервере. В ситуациях, когда форма не выполняется на сервере, например при применении режима отрисовки интерактивного сервера непосредственно к компоненту, явное назначение проверка от модели не требуется, так как Blazor сохраняет состояние элемента <select> на клиенте.

Starship3.razor:

@page "/starship-3"
@inject ILogger<Starship3> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship3">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <label>
            Description (optional): 
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification: 
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">
                    Select classification ...
                </option>
                <option checked="@(Model!.Classification == "Exploration")" 
                    value="Exploration">
                    Exploration
                </option>
                <option checked="@(Model!.Classification == "Diplomacy")" 
                    value="Diplomacy">
                    Diplomacy
                </option>
                <option checked="@(Model!.Classification == "Defense")" 
                    value="Defense">
                    Defense
                </option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation: 
            <InputNumber @bind-Value="Model!.MaximumAccommodation" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval: 
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
        </label>
    </div>
    <div>
        <label>
            Production Date: 
            <InputDate @bind-Value="Model!.ProductionDate" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        Logger.LogInformation("Id = {Id} Description = {Description} " +
            "Classification = {Classification} MaximumAccommodation = " +
            "{MaximumAccommodation} IsValidatedDesign = " +
            "{IsValidatedDesign} ProductionDate = {ProductionDate}",
            Model?.Id, Model?.Description, Model?.Classification,
            Model?.MaximumAccommodation, Model?.IsValidatedDesign,
            Model?.ProductionDate);
    }
}
@page "/starship-3"
@inject ILogger<Starship3> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="Model!.MaximumAccommodation" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
        </label>
    </div>
    <div>
        <label>
            Production Date:
            <InputDate @bind-Value="Model!.ProductionDate" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        Logger.LogInformation("Id = {Id} Description = {Description} " +
            "Classification = {Classification} MaximumAccommodation = " +
            "{MaximumAccommodation} IsValidatedDesign = " +
            "{IsValidatedDesign} ProductionDate = {ProductionDate}", 
            Model?.Id, Model?.Description, Model?.Classification, 
            Model?.MaximumAccommodation, Model?.IsValidatedDesign, 
            Model?.ProductionDate);
    }
}

EditForm в предыдущем примере создает EditContext на основе назначенного экземпляра Starship (Model="...") и обрабатывает допустимую форму. В следующем примере показано, как назначить EditContext форму и проверить отправку формы.

В следующем примере :

  • Сокращенная версия более ранней Starfleet Starship Database формы (Starship3 компонента) используется, которая принимает только значение для идентификатора звездочки. Другие Starship свойства получают допустимые значения по умолчанию при создании экземпляра Starship типа.
  • Метод Submit выполняется при нажатии кнопки Submit.
  • Форма проверяется путем вызова EditContext.Validate в методе Submit.
  • В зависимости от результата проверки выполняется регистрация данных в журнале.

Примечание.

Submit в следующем примере демонстрируется как асинхронный метод, так как хранение значений форм часто использует асинхронные вызовы (await ...). Если форма используется в тестовом приложении как показано, Submit просто выполняется синхронно. При тестировании игнорируйте следующее предупреждение сборки:

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. ...

Starship4.razor:

@page "/starship-4"
@inject ILogger<Starship4> Logger

<EditForm EditContext="editContext" OnSubmit="Submit" FormName="Starship4">
    <DataAnnotationsValidator />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??=
            new()
                {
                    Id = "NCC-1701",
                    Classification = "Exploration",
                    MaximumAccommodation = 150,
                    IsValidatedDesign = true,
                    ProductionDate = new DateTime(2245, 4, 11)
                };
        editContext = new(Model);
    }

    private async Task Submit()
    {
        if (editContext != null && editContext.Validate())
        {
            Logger.LogInformation("Submit called: Form is valid");

            // await ...
        }
        else
        {
            Logger.LogInformation("Submit called: Form is INVALID");
        }
    }
}
@page "/starship-4"
@inject ILogger<Starship4> Logger

<EditForm EditContext="editContext" OnSubmit="Submit">
    <DataAnnotationsValidator />
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

    private Starship Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??= 
            new()
            {
                Id = "NCC-1701",
                Classification = "Exploration",
                MaximumAccommodation = 150,
                IsValidatedDesign = true,
                ProductionDate = new DateTime(2245, 4, 11)
            };
        editContext = new(Model);
    }

    private async Task Submit()
    {
        if (editContext != null && editContext.Validate())
        {
            Logger.LogInformation("Submit called: Form is valid");

            // await ...
        }
        else
        {
            Logger.LogInformation("Submit called: Form is INVALID");
        }
    }
}

Примечание.

EditContext Изменение после назначения не поддерживается.

Выбор нескольких вариантов с компонентом InputSelect

Привязка поддерживает выбор параметра multiple с компонентом InputSelect<TValue>. Событие @onchange предоставляет массив выбранных параметров через аргументы события (ChangeEventArgs). Значение должно быть привязано к типу массива, а привязка к типу массива делает атрибут multiple необязательным в теге InputSelect<TValue>.

В следующем примере пользователь должен выбрать по крайней мере две классификации космических кораблей, но не более трех.

Starship5.razor:

@page "/starship-5"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship5> Logger

<h1>Bind Multiple <code>InputSelect</code> Example</h1>

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship5">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Select classifications (Minimum: 2, Maximum: 3):
            <InputSelect @bind-Value="Model!.SelectedClassification">
                <option value="@Classification.Exploration">Exploration</option>
                <option value="@Classification.Diplomacy">Diplomacy</option>
                <option value="@Classification.Defense">Defense</option>
                <option value="@Classification.Research">Research</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@if (Model?.SelectedClassification?.Length > 0)
{
    <div>@string.Join(", ", Model.SelectedClassification)</div>
}

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model = new();
        editContext = new(Model);
    }

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    private class Starship
    {
        [Required]
        [MinLength(2, ErrorMessage = "Select at least two classifications.")]
        [MaxLength(3, ErrorMessage = "Select no more than three classifications.")]
        public Classification[]? SelectedClassification { get; set; } =
            new[] { Classification.None };
    }

    private enum Classification { None, Exploration, Diplomacy, Defense, Research }
}
@page "/starship-5"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship5> Logger

<h1>Bind Multiple <code>InputSelect</code> Example</h1>

<EditForm EditContext="editContext" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Select classifications (Minimum: 2, Maximum: 3):
            <InputSelect @bind-Value="Model!.SelectedClassification">
                <option value="@Classification.Exploration">Exploration</option>
                <option value="@Classification.Diplomacy">Diplomacy</option>
                <option value="@Classification.Defense">Defense</option>
                <option value="@Classification.Research">Research</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@if (Model?.SelectedClassification?.Length > 0)
{
    <div>@string.Join(", ", Model.SelectedClassification)</div>
}

@code {
    private EditContext? editContext;

    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
    }

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    private class Starship
    {
        [Required]
        [MinLength(2, ErrorMessage = "Select at least two classifications.")]
        [MaxLength(3, ErrorMessage = "Select no more than three classifications.")]
        public Classification[]? SelectedClassification { get; set; } =
            new[] { Classification.None };
    }

    private enum Classification { None, Exploration, Diplomacy, Defense, Research }
}

Сведения о том, как пустые строки и значения null обрабатываются в привязке данных, см. в разделе Параметры InputSelect привязки для значений null объектов C#.

Привязка параметров InputSelect к значениям null объекта C#

Сведения о том, как пустые строки и значения null обрабатываются в привязке к данным, см. в статье Привязка к данным в ASP.NET Core Blazor.

Поддержка отображаемого имени

Несколько встроенных компонентов поддерживают отображаемые имена с помощью параметра InputBase<TValue>.DisplayName.

В форме Starfleet Starship Database (компонент Starship3) раздела Пример формы дата производства нового космического корабля не имеет отображаемого имени:

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" />
</label>

Если поле содержит недопустимую дату при отправке формы, то в сообщении об ошибке не отображается понятное имя. Имя поля ProductionDate не содержит пробел между Production и Date, если оно отображается в сводке проверки:

Поле ProductionDate должно быть датой.

Задайте для свойства DisplayName понятное имя с пробелом между словами Production и Date:

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        DisplayName="Production Date" />
</label>

В сводке проверки отображается понятное имя, если значение поля недопустимо:

Поле Production Date должно быть датой.

Поддержка шаблонов сообщений об ошибках

InputDate<TValue> и InputNumber<TValue> поддерживают шаблоны сообщений об ошибках:

В форме Starfleet Starship Database (компоненте Starship3) в разделе Пример формы с назначенным понятным отображаемым именем поле Production Date выдает сообщение об ошибке, используя следующий шаблон сообщения об ошибке по умолчанию:

The {0} field must be a date.

Расположение заполнителя {0} — это место, где появляется значение свойства DisplayName при отображении ошибки пользователю.

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        DisplayName="Production Date" />
</label>

Поле Production Date должно быть датой.

Назначьте пользовательский шаблон для ParsingErrorMessage, чтобы предоставлялось настраиваемое сообщение:

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        DisplayName="Production Date" 
        ParsingErrorMessage="The {0} field has an incorrect date value." />
</label>

Поле Production Date имеет неверное значение даты.

В форме Starfleet Starship Database (компонент Starship3) в разделе Пример формы используется шаблон сообщения об ошибке по умолчанию:

The {0} field must be a date.

Расположение заполнителя {0} — это место, где появляется значение свойства DisplayName при отображении ошибки пользователю.

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" />
</label>

Поле ProductionDate должно быть датой.

Назначьте пользовательский шаблон для ParsingErrorMessage, чтобы предоставлялось настраиваемое сообщение:

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        ParsingErrorMessage="The {0} field has an incorrect date value." />
</label>

Поле ProductionDate имеет неверное значение даты.