привязка Blazor основных форм ASP.NET
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 8 этой статьи.
В этой статье объясняется, как использовать привязку в Blazor формах.
Модель EditForm
/EditContext
EditContext Создается EditForm на основе назначенного объекта в виде каскадного значения для других компонентов в форме. Отслеживает EditContext метаданные процесса редактирования, включая измененные поля формы и текущие сообщения проверки. Назначение элементу EditForm.Model или EditForm.EditContext может привязывать форму к данным.
Привязка модели
Назначение элементу EditForm.Model:
<EditForm ... Model="Model" ...>
...
</EditForm>
@code {
[SupplyParameterFromForm]
public Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
}
<EditForm ... Model="Model" ...>
...
</EditForm>
@code {
public Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
}
Примечание.
Большинство примеров модели форм этой статьи привязывают формы к свойствам C#, но привязка полей C# также поддерживается.
Привязка контекста
Назначение элементу EditForm.EditContext:
<EditForm ... EditContext="editContext" ...>
...
</EditForm>
@code {
private EditContext? editContext;
[SupplyParameterFromForm]
public Starship? Model { get; set; }
protected override void OnInitialized()
{
Model ??= new();
editContext = new(Model);
}
}
<EditForm ... EditContext="editContext" ...>
...
</EditForm>
@code {
private EditContext? editContext;
public Starship? Model { get; set; }
protected override void OnInitialized()
{
Model ??= new();
editContext = new(Model);
}
}
Назначайте элементу EditFormлибоEditContext, либоModel. Если оба назначены, возникает ошибка среды выполнения.
Поддерживаемые типы
Привязка поддерживает:
- Примитивные типы
- Коллекции
- Сложные типы
- Рекурсивные типы
- Типы с конструкторами
- Перечисления
Вы также можете использовать [DataMember]
атрибуты и [IgnoreDataMember]
атрибуты для настройки привязки модели. Используйте эти атрибуты, чтобы переименовать свойства, игнорировать свойства и пометить их как обязательные.
Дополнительные параметры привязки
Дополнительные параметры привязки модели доступны при RazorComponentsServiceOptions вызове AddRazorComponents:
- MaxFormMappingCollectionSize: максимальное количество элементов, разрешенных в коллекции форм.
- MaxFormMappingRecursionDepth: максимальная глубина, разрешенная при рекурсивном сопоставлении данных формы.
- MaxFormMappingErrorCount: максимальное количество ошибок, разрешенных при сопоставлении данных формы.
- MaxFormMappingKeySize: максимальный размер буфера, используемого для чтения ключей данных формы.
Ниже показаны значения по умолчанию, назначенные платформой:
builder.Services.AddRazorComponents(options =>
{
options.FormMappingUseCurrentCulture = true;
options.MaxFormMappingCollectionSize = 1024;
options.MaxFormMappingErrorCount = 200;
options.MaxFormMappingKeySize = 1024 * 2;
options.MaxFormMappingRecursionDepth = 64;
}).AddInteractiveServerComponents();
Имена форм
FormName Используйте параметр для назначения имени формы. Имена форм должны быть уникальными для привязки данных модели. Следующая форма называется RomulanAle
:
<EditForm ... FormName="RomulanAle" ...>
...
</EditForm>
Укажите имя формы:
- Требуется для всех форм, отправленных статически отрисованными на стороне сервера компонентами.
- Не требуется для форм, отправленных интерактивными компонентами, которые включают формы в Blazor WebAssembly приложениях и компонентах с интерактивным режимом отрисовки. Однако мы рекомендуем указать уникальное имя формы для каждой формы, чтобы предотвратить публикацию ошибок формы во время выполнения, если интерактивность когда-либо удаляется для формы.
Имя формы проверка только при публикации формы в конечную точку в качестве традиционного HTTP-запроса POST из статического серверного компонента. Платформа не создает исключение в точке отрисовки формы, но только в момент прибытия HTTP POST и не указывает имя формы.
По умолчанию существует форма без имени (пустая строка) область над корневым компонентом приложения, который достаточно, если в приложении нет конфликтов имен форм. Если возможны столкновения имен форм, например при включении формы из библиотеки, и у вас нет элемента управления именем формы, используемого разработчиком библиотеки, укажите имя формы область с FormMappingScope компонентом в Blazor основном проекте веб-приложения.
В следующем примере HelloFormFromLibrary
компонент имеет форму с именем Hello
и находится в библиотеке.
HelloFormFromLibrary.razor
:
<EditForm FormName="Hello" Model="this" OnSubmit="Submit">
<InputText @bind-Value="Name" />
<button type="submit">Submit</button>
</EditForm>
@if (submitted)
{
<p>Hello @Name from the library's form!</p>
}
@code {
bool submitted = false;
[SupplyParameterFromForm]
public string? Name { get; set; }
private void Submit() => submitted = true;
}
NamedFormsWithScope
Следующий компонент использует компонент библиотекиHelloFormFromLibrary
, а также имеет форму с именемHello
. FormMappingScope Имя компонента область предназначено ParentContext
для любых форм, предоставляемых компонентомHelloFormFromLibrary
. Хотя обе формы в этом примере имеют имя формы (Hello
), имена форм не сталкиваются и события направляются в правильную форму для событий POST формы.
NamedFormsWithScope.razor
:
@page "/named-forms-with-scope"
<div>Hello form from a library</div>
<FormMappingScope Name="ParentContext">
<HelloFormFromLibrary />
</FormMappingScope>
<div>Hello form using the same form name</div>
<EditForm FormName="Hello" Model="this" OnSubmit="Submit">
<InputText @bind-Value="Name" />
<button type="submit">Submit</button>
</EditForm>
@if (submitted)
{
<p>Hello @Name from the app form!</p>
}
@code {
bool submitted = false;
[SupplyParameterFromForm]
public string? Name { get; set; }
private void Submit() => submitted = true;
}
Укажите параметр из формы ([SupplyParameterFromForm]
)
Атрибут [SupplyParameterFromForm]
указывает, что значение связанного свойства должно быть предоставлено из данных формы для формы. Данные в запросе, который соответствует имени свойства, привязан к свойству. Входные данные на InputBase<TValue>
основе создания имен значений формы, которые соответствуют именам Blazor , которые используются для привязки модели.
Для атрибута можно указать следующие параметры привязки [SupplyParameterFromForm]
формы:
- Name: возвращает или задает имя параметра. Имя используется для определения префикса для сопоставления данных формы и определения необходимости привязки значения.
- FormName: возвращает или задает имя обработчика. Имя используется для сопоставления параметра с формой по имени формы для определения необходимости привязки значения.
Следующий пример независимо привязывает две формы к их моделям по имени формы.
Starship6.razor
:
@page "/starship-6"
@inject ILogger<Starship6> Logger
<EditForm Model="Model1" OnSubmit="Submit1" FormName="Holodeck1">
<div>
<label>
Holodeck 1 Identifier:
<InputText @bind-Value="Model1!.Id" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
<EditForm Model="Model2" OnSubmit="Submit2" FormName="Holodeck2">
<div>
<label>
Holodeck 2 Identifier:
<InputText @bind-Value="Model2!.Id" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
@code {
[SupplyParameterFromForm(FormName = "Holodeck1")]
public Holodeck? Model1 { get; set; }
[SupplyParameterFromForm(FormName = "Holodeck2")]
public Holodeck? Model2 { get; set; }
protected override void OnInitialized()
{
Model1 ??= new();
Model2 ??= new();
}
private void Submit1()
{
Logger.LogInformation("Submit1: Id = {Id}", Model1?.Id);
}
private void Submit2()
{
Logger.LogInformation("Submit2: Id = {Id}", Model2?.Id);
}
public class Holodeck
{
public string? Id { get; set; }
}
}
Вложенные и привязки формы
В следующем руководстве показано, как вложить и привязать дочерние формы.
Следующий класс сведений о корабле (ShipDetails
) содержит описание и длину для подчиненной формы.
ShipDetails.cs
:
namespace BlazorSample;
public class ShipDetails
{
public string? Description { get; set; }
public int? Length { get; set; }
}
Ship
Следующий класс называет идентификатор (Id
) и содержит сведения о доставке.
Ship.cs
:
namespace BlazorSample
{
public class Ship
{
public string? Id { get; set; }
public ShipDetails Details { get; set; } = new();
}
}
Следующая подформа используется для редактирования значений ShipDetails
типа. Это реализуется путем Editor<T> наследования в верхней части компонента. Editor<T>гарантирует, что дочерний компонент создает правильные имена полей формы на основе модели (T
), где T
в следующем примере.ShipDetails
StarshipSubform.razor
:
@inherits Editor<ShipDetails>
<div>
<label>
Description:
<InputText @bind-Value="Value!.Description" />
</label>
</div>
<div>
<label>
Length:
<InputNumber @bind-Value="Value!.Length" />
</label>
</div>
Основная форма привязана к классу Ship
. Компонент StarshipSubform
используется для редактирования сведений о доставке, привязанных как Model!.Details
.
Starship7.razor
:
@page "/starship-7"
@inject ILogger<Starship7> Logger
<EditForm Model="Model" OnSubmit="Submit" FormName="Starship7">
<div>
<label>
Identifier:
<InputText @bind-Value="Model!.Id" />
</label>
</div>
<StarshipSubform @bind-Value="Model!.Details" />
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
@code {
[SupplyParameterFromForm]
public Ship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
private void Submit()
{
Logger.LogInformation("Id = {Id} Desc = {Description} Length = {Length}",
Model?.Id, Model?.Details?.Description, Model?.Details?.Length);
}
}
Сценарии ошибок сопоставления расширенных форм
Платформа создает экземпляр и заполняет FormMappingContext форму, которая является контекстом, связанным с операцией сопоставления данной формы. Каждое сопоставление область (определяется компонентомFormMappingScope) создает экземплярыFormMappingContext. Каждый раз при [SupplyParameterFromForm]
запросе контекста значения платформа заполняет FormMappingContext попытку значения и любые ошибки сопоставления.
Разработчики не должны взаимодействовать FormMappingContext напрямую, так как это главным образом источник данных для InputBase<TValue>, EditContextа также другие внутренние реализации для отображения ошибок сопоставления в виде ошибок проверки. В расширенных пользовательских сценариях разработчики могут напрямую [CascadingParameter]
обращаться FormMappingContext к пользовательскому коду, который использует попытки значений и ошибок сопоставления.
Переключатели
Пример в этом разделе основан на Starfleet Starship Database
форме (Starship3
компоненте) раздела формы примера этой статьи.
Добавьте в приложение указанные ниже типы enum
. Создайте файл для их хранения или добавьте их в файл Starship.cs
.
public class ComponentEnums
{
public enum Manufacturer { SpaceX, NASA, ULA, VirginGalactic, Unknown }
public enum Color { ImperialRed, SpacecruiserGreen, StarshipBlue, VoyagerOrange }
public enum Engine { Ion, Plasma, Fusion, Warp }
}
Сделайте класс доступным для ComponentEnums
следующих элементов:
Starship
модель вStarship.cs
(например,using static ComponentEnums;
).Starfleet Starship Database
форма (Starship3.razor
например,@using static ComponentEnums
).
Используйте компоненты InputRadio<TValue> с компонентом InputRadioGroup<TValue>, чтобы создать группу переключателей. В следующем примере свойства добавляются в Starship
модель, описанную в разделе формы "Пример" статьи "Входные компоненты".
[Required]
[Range(typeof(Manufacturer), nameof(Manufacturer.SpaceX),
nameof(Manufacturer.VirginGalactic), ErrorMessage = "Pick a manufacturer.")]
public Manufacturer Manufacturer { get; set; } = Manufacturer.Unknown;
[Required, EnumDataType(typeof(Color))]
public Color? Color { get; set; } = null;
[Required, EnumDataType(typeof(Engine))]
public Engine? Engine { get; set; } = null;
Starfleet Starship Database
Обновите форму (Starship3
компонент) раздела "Пример формы" статьи "Входные компоненты". Добавьте компоненты для создания следующих элементов:
- группы переключателей для выбора производителя корабля;
- вложенной группы переключателей для выбора двигателя и цвета корабля.
Примечание.
Вложенные группы переключателей часто не используются в формах, поскольку они могут привести к неупорядоченному расположению элементов управления формы, которое может запутать пользователей. Однако бывают случаи, когда разумно использовать их в пользовательском интерфейсе, например в следующем примере, в котором объединены рекомендации для двух значений, указываемых пользователем, — двигателя и цвета корабля. По правилам проверки формы необходимо указать один двигатель и один цвет. На макете формы используются вложенные объекты InputRadioGroup<TValue> для связывания рекомендаций по двигателю и цвету. Однако пользователь может объединить любой двигатель с любым цветом для отправки формы.
Примечание.
Убедитесь, что класс доступен компоненту ComponentEnums
в следующем примере:
@using static ComponentEnums
<fieldset>
<legend>Manufacturer</legend>
<InputRadioGroup @bind-Value="Model!.Manufacturer">
@foreach (var manufacturer in Enum.GetValues<Manufacturer>())
{
<div>
<label>
<InputRadio Value="manufacturer" />
@manufacturer
</label>
</div>
}
</InputRadioGroup>
</fieldset>
<fieldset>
<legend>Engine and Color</legend>
<p>
Engine and color pairs are recommended, but any
combination of engine and color is allowed.
</p>
<InputRadioGroup Name="engine" @bind-Value="Model!.Engine">
<InputRadioGroup Name="color" @bind-Value="Model!.Color">
<div style="margin-bottom:5px">
<div>
<label>
<InputRadio Name="engine" Value="Engine.Ion" />
Ion
</label>
</div>
<div>
<label>
<InputRadio Name="color" Value="Color.ImperialRed" />
Imperial Red
</label>
</div>
</div>
<div style="margin-bottom:5px">
<div>
<label>
<InputRadio Name="engine" Value="Engine.Plasma" />
Plasma
</label>
</div>
<div>
<label>
<InputRadio Name="color" Value="Color.SpacecruiserGreen" />
Spacecruiser Green
</label>
</div>
</div>
<div style="margin-bottom:5px">
<div>
<label>
<InputRadio Name="engine" Value="Engine.Fusion" />
Fusion
</label>
</div>
<div>
<label>
<InputRadio Name="color" Value="Color.StarshipBlue" />
Starship Blue
</label>
</div>
</div>
<div style="margin-bottom:5px">
<div>
<label>
<InputRadio Name="engine" Value="Engine.Warp" />
Warp
</label>
</div>
<div>
<label>
<InputRadio Name="color" Value="Color.VoyagerOrange" />
Voyager Orange
</label>
</div>
</div>
</InputRadioGroup>
</InputRadioGroup>
</fieldset>
Примечание.
Если опустить Name
, компоненты InputRadio<TValue> будут группироваться по последнему предку.
Если вы реализовали предыдущую Razor разметку в Starship3
компоненте раздела "Пример формы" статьи "Входные компоненты", обновите ведение журнала для Submit
метода:
Logger.LogInformation("Id = {Id} Description = {Description} " +
"Classification = {Classification} MaximumAccommodation = " +
"{MaximumAccommodation} IsValidatedDesign = " +
"{IsValidatedDesign} ProductionDate = {ProductionDate} " +
"Manufacturer = {Manufacturer}, Engine = {Engine}, " +
"Color = {Color}",
Model?.Id, Model?.Description, Model?.Classification,
Model?.MaximumAccommodation, Model?.IsValidatedDesign,
Model?.ProductionDate, Model?.Manufacturer, Model?.Engine,
Model?.Color);
При работе с переключателями в форме привязка данных обрабатывается иначе, чем другие элементы, так как переключатели оцениваются как группа. Значение каждого переключателя является фиксированным, но значение группы переключателей является значением выбранного переключателя. В приведенном ниже примере показано, как выполнить следующие задачи.
- Обработка привязки данных для группы переключателей.
- Поддержка проверки с помощью пользовательского компонента InputRadio<TValue>.
InputRadio.razor
:
@using System.Globalization
@inherits InputBase<TValue>
@typeparam TValue
<input @attributes="AdditionalAttributes" type="radio" value="@SelectedValue"
checked="@(SelectedValue.Equals(Value))" @onchange="OnChange" />
@code {
[Parameter]
public TValue SelectedValue { get; set; }
private void OnChange(ChangeEventArgs args)
{
CurrentValueAsString = args.Value.ToString();
}
protected override bool TryParseValueFromString(string value,
out TValue result, out string errorMessage)
{
var success = BindConverter.TryConvertTo<TValue>(
value, CultureInfo.CurrentCulture, out var parsedValue);
if (success)
{
result = parsedValue;
errorMessage = null;
return true;
}
else
{
result = default;
errorMessage = "The field isn't valid.";
return false;
}
}
}
Дополнительные сведения о параметрах универсального типа (@typeparam
) см. в следующих статьях:
- Справочник по синтаксису Razor для ASP.NET Core
- Компоненты Razor ASP.NET Core
- Шаблонные компоненты ASP.NET Core Blazor
Используйте следующую модель.
StarshipModel.cs
:
using System.ComponentModel.DataAnnotations;
namespace BlazorServer80
{
public class Model
{
[Range(1, 5)]
public int Rating { get; set; }
}
}
Следующий компонент RadioButtonExample
использует предыдущий компонент InputRadio
для получения и проверки оценки пользователя:
RadioButtonExample.razor
:
@page "/radio-button-example"
@using System.ComponentModel.DataAnnotations
@using Microsoft.Extensions.Logging
@inject ILogger<RadioButtonExample> Logger
<h1>Radio Button Example</h1>
<EditForm Model="Model" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
@for (int i = 1; i <= 5; i++)
{
<div>
<label>
<InputRadio name="rate" SelectedValue="i"
@bind-Value="Model.Rating" />
@i
</label>
</div>
}
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
<div>@Model.Rating</div>
@code {
public StarshipModel Model { get; set; }
protected override void OnInitialized() => Model ??= new();
private void HandleValidSubmit()
{
Logger.LogInformation("HandleValidSubmit called");
}
}
ASP.NET Core
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по