Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.
Ostrzeżenie
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.
W tym artykule wyjaśniono, jak używać powiązania w Blazor formularzach.
EditForm
/
EditContext model
EditForm tworzy element EditContext na podstawie przypisanego obiektu jako wartość kaskadową dla innych komponentów w formularzu. Śledzi EditContext metadane dotyczące procesu edycji, w tym pola formularza, które zostały zmodyfikowane, oraz bieżące komunikaty sprawdzania poprawności. Przypisanie do obiektu EditForm.Model lub EditForm.EditContext może powiązać formularz z danymi.
Wiązanie modelu
Przypisanie do EditForm.Model:
<EditForm ... Model="Model" ...>
...
</EditForm>
@code {
[SupplyParameterFromForm]
private 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();
}
Uwaga
Większość przykładów modelu formularzy tego artykułu wiąże formularze z właściwościami języka C#, ale obsługiwane jest również powiązanie pól języka C#.
Powiązanie kontekstu
Przypisanie do EditForm.EditContext:
<EditForm ... EditContext="editContext" ...>
...
</EditForm>
@code {
private EditContext? editContext;
[SupplyParameterFromForm]
private 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);
}
}
Przypisz do albo , albo . Jeśli oba te elementy zostaną przypisane, zostanie zgłoszony błąd środowiska uruchomieniowego.
Obsługiwane typy
Obsługiwane powiązania:
- Typy pierwotne
- Kolekcje
- Typy złożone
- Typy rekursywne
- Typy z konstruktorami
- Wyliczenia
Można również użyć atrybutów [DataMember] i [IgnoreDataMember], aby dostosować wiązanie modelu. Użyj tych atrybutów, aby zmienić nazwy właściwości, zignorować właściwości i oznaczyć właściwości zgodnie z potrzebami.
W przypadku powiązania typu z parametrami konstruktora, jeśli parametr konstruktora ma taką samą nazwę jak właściwość, parametr konstruktora ma priorytet. Moduł mapujący używa jawnie określonego elementu DataMember.Name, jeśli jest obecny, jako nazwy pola formularza, ale poza tym ignoruje atrybuty mapowania właściwości. Parametry konstruktora są zawsze wymagane.
Dodatkowe opcje powiązania
Dodatkowe opcje wiązania modelu są dostępne w elemencie RazorComponentsServiceOptions podczas wywoływania AddRazorComponents:
- MaxFormMappingCollectionSize: Maksymalna liczba elementów dozwolonych w kolekcji formularzy.
- MaxFormMappingRecursionDepth: Maksymalna głębokość dozwolona podczas cyklicznego mapowania danych formularza.
- MaxFormMappingErrorCount: Maksymalna liczba błędów dozwolonych podczas mapowania danych formularza.
- MaxFormMappingKeySize: maksymalny rozmiar buforu używanego do odczytywania kluczy danych formularza.
Poniżej przedstawiono wartości domyślne przypisane przez strukturę:
builder.Services.AddRazorComponents(options =>
{
options.FormMappingUseCurrentCulture = true;
options.MaxFormMappingCollectionSize = 1024;
options.MaxFormMappingErrorCount = 200;
options.MaxFormMappingKeySize = 1024 * 2;
options.MaxFormMappingRecursionDepth = 64;
}).AddInteractiveServerComponents();
Nazwy formularzy
Użyj parametru , FormName aby przypisać nazwę formularza. Nazwy formularzy muszą być unikatowe w celu powiązania danych modelu. Następujący formularz nosi nazwę RomulanAle:
<EditForm ... FormName="RomulanAle" ...>
...
</EditForm>
Podawanie nazwy formularza:
- Jest to wymagane w przypadku wszystkich formularzy wysyłanych przez statycznie renderowane komponenty serwerowe.
- Nie jest wymagane w przypadku formularzy przesyłanych przez składniki renderowane interaktywnie, w tym formularze w Blazor WebAssembly aplikacjach i składnikach z trybem renderowania interakcyjnego. Zalecamy jednak nadanie unikalnej nazwy każdemu formularzowi, aby zapobiec błędom podczas przesyłania formularza w czasie działania, jeśli formularz kiedykolwiek utraci interaktywność.
Nazwa formularza jest sprawdzana tylko wtedy, gdy formularz jest publikowany w punkcie końcowym jako tradycyjne żądanie HTTP POST ze statycznie renderowanego składnika po stronie serwera. Struktura nie zgłasza wyjątku w momencie renderowania formularza, ale tylko w momencie nadejścia żądania HTTP POST i nie określa nazwy formularza.
Nad głównym komponentem aplikacji istnieje nienazwany zakres formularzy (pusty ciąg znaków), co jest wystarczające, jeśli w aplikacji nie występują kolizje nazw formularzy. Jeśli możliwe są konflikty nazw formularzy, na przykład podczas dołączania formularza z biblioteki, a nie masz wpływu na nazwę formularza używaną przez twórcę biblioteki, określ zakres nazw formularzy za pomocą komponentu FormMappingScope w głównym projekcie Blazor Web App.
W poniższym przykładzie HelloFormFromLibrary składnik ma postać o nazwie Hello i znajduje się w bibliotece.
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]
private string? Name { get; set; }
private void Submit() => submitted = true;
}
Poniższy NamedFormsWithScope składnik używa składnika biblioteki HelloFormFromLibrary , a także ma formularz o nazwie Hello. Nazwa zakresu komponentu FormMappingScope dla wszystkich formularzy dostarczanych przez komponent HelloFormFromLibrary to ParentContext. Mimo że oba formularze w tym przykładzie mają tę samą nazwę formularza (Hello), nazwy formularzy nie powodują konfliktu, a zdarzenia są kierowane do właściwego formularza w przypadku zdarzeń POST formularza.
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]
private string? Name { get; set; }
private void Submit() => submitted = true;
}
Podaj parametr z formularza ([SupplyParameterFromForm])
Atrybut [SupplyParameterFromForm] wskazuje, że wartość skojarzonej właściwości powinna pochodzić z danych tego formularza. Dane w żądaniu, które pasują do nazwy właściwości, są powiązane z właściwością. Pola wejściowe oparte na InputBase<TValue> generują nazwy wartości formularza zgodne z nazwami używanymi przez Blazor do wiązania modelu. W przeciwieństwie do właściwości parametrów składnika ([Parameter]) właściwości oznaczone adnotacją [SupplyParameterFromForm] nie muszą być oznaczone jako public.
Blazor mapowanie formularza przy użyciu [SupplyParameterFromForm] nie używa wiązania modelu MVC. Atrybuty w Microsoft.AspNetCore.Mvc.ModelBinding przestrzeni nazw, takie jak [BindNever] i [BindRequired], nie są obsługiwane. Nie używaj tych atrybutów, aby zapobiec przepostowaniu. Zamiast tego należy użyć dedykowanego modelu formularza, modelu wyświetlania lub obiektu transferu danych (DTO), który zawiera tylko właściwości, które użytkownicy mogą modyfikować. Aby uzyskać więcej informacji, zobacz Ograniczanie ataków typu overposting.
Do atrybutu [SupplyParameterFromForm]można określić następujące parametry powiązania formularza:
- Name: Pobiera lub ustawia nazwę parametru. Nazwa służy do określania prefiksu używanego do dopasowania danych formularza i decydowania, czy wartość musi być powiązana.
- FormName: Pobiera lub ustawia nazwę programu obsługi. Nazwa jest używana do dopasowania parametru do formularza na podstawie nazwy formularza w celu określenia, czy wartość należy powiązać.
Poniższy przykład niezależnie powiązuje dwa formularze z odpowiednimi modelami na podstawie nazwy formularza.
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")]
private Holodeck? Model1 { get; set; }
[SupplyParameterFromForm(FormName = "Holodeck2")]
private 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; }
}
}
@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")]
private Holodeck? Model1 { get; set; }
[SupplyParameterFromForm(FormName = "Holodeck2")]
private 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; }
}
}
Zagnieżdżanie i wiązanie formularzy
Poniższe instrukcje pokazują, jak zagnieżdżać i powiązać formularze podrzędne.
Poniższa klasa szczegółów statku (ShipDetails) zawiera opis oraz długość podformularza.
ShipDetails.cs:
namespace BlazorSample;
public class ShipDetails
{
public string? Description { get; set; }
public int? Length { get; set; }
}
namespace BlazorSample;
public class ShipDetails
{
public string? Description { get; set; }
public int? Length { get; set; }
}
Poniższa klasa Ship określa identyfikator (Id) i zawiera szczegóły statku.
Ship.cs:
namespace BlazorSample
{
public class Ship
{
public string? Id { get; set; }
public ShipDetails Details { get; set; } = new();
}
}
namespace BlazorSample
{
public class Ship
{
public string? Id { get; set; }
public ShipDetails Details { get; set; } = new();
}
}
Poniższy podformularz jest używany do edytowania wartości typu ShipDetails. Jest to realizowane przez dziedziczenie Editor<T> na początku komponentu.
Editor<T>gwarantuje, że składnik podrzędny generuje poprawne nazwy pól formularza na podstawie modelu (T), gdzie T w poniższym przykładzie jest .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>
@inherits Editor<ShipDetails>
<div>
<label>
Description:
<InputText @bind-Value="Value!.Description" />
</label>
</div>
<div>
<label>
Length:
<InputNumber @bind-Value="Value!.Length" />
</label>
</div>
Formularz główny jest powiązany z klasą Ship . Komponent StarshipSubform służy do edytowania szczegółów statku, powiązany jako 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]
private 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);
}
@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]
private 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);
}
Zainicjuj dane formularza za pomocą statycznego SSR
Gdy składnik używa statycznego SSR, metoda cyklu życia OnInitialized{Async} lifecycle method oraz metoda cyklu życia OnParametersSet{Async} lifecycle method są wywoływane podczas początkowego renderowania składnika oraz przy każdym żądaniu POST formularza wysyłanym do serwera. Aby zainicjować wartości modelu formularza, upewnij się, że model ma już dane, zanim przypiszesz nowe wartości modelu w OnParametersSet{Async}, co ilustruje poniższy przykład.
StarshipInit.razor:
@page "/starship-init"
@inject ILogger<StarshipInit> Logger
<EditForm Model="Model" OnValidSubmit="Submit" FormName="StarshipInit">
<div>
<label>
Identifier:
<InputText @bind-Value="Model!.Id" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
@code {
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
protected override void OnParametersSet()
{
if (Model!.Id == default)
{
LoadData();
}
}
private void LoadData()
{
Model!.Id = "Set by LoadData";
}
private void Submit()
{
Logger.LogInformation("Id = {Id}", Model?.Id);
}
public class Starship
{
public string? Id { get; set; }
}
}
Zaawansowane scenariusze błędów mapowania formularzy
Framework tworzy instancję i wypełnia element FormMappingContext dla formularza, który jest kontekstem skojarzonym z operacją mapowania danego formularza. Każdy zakres mapowania (zdefiniowany przez komponent FormMappingScope) tworzy instancję FormMappingContext. Za każdym razem, gdy element [SupplyParameterFromForm] żąda od kontekstu wartości, platforma wypełnia element FormMappingContext próbowaną wartością oraz wszelkimi błędami mapowania.
Nie oczekuje się, że deweloperzy będą wchodzić w bezpośrednią interakcję z FormMappingContext, ponieważ jest to głównie źródło danych dla InputBase<TValue>, EditContext i innych wewnętrznych implementacji do wyświetlania błędów mapowania jako błędów walidacji. W zaawansowanych niestandardowych scenariuszach deweloperzy mogą uzyskać bezpośredni dostęp do FormMappingContext jako [CascadingParameter], aby pisać niestandardowy kod, który wykorzystuje wartości, których próbowano użyć, oraz błędy mapowania.
Niestandardowe składniki wejściowe
W przypadku niestandardowych scenariuszy przetwarzania danych wejściowych w poniższych podsekcjach przedstawiono niestandardowe składniki wejściowe:
Komponent wejściowy oparty na
InputBase<T>: Komponent dziedziczy po InputBase<TValue>, który zapewnia podstawową implementację wiązań, wywołań zwrotnych i walidacji. Komponenty dziedziczące po InputBase<TValue> muszą być używane w formularzu Blazor (EditForm).Składnik wejściowy z pełną kontrolą dewelopera: składnik przejmuje pełną kontrolę nad przetwarzaniem wejściowym. Kod składnika musi zarządzać powiązaniami, wywołaniami zwrotnymi i walidacją. Składnik może być używany wewnątrz formularza lub poza nim Blazor .
Zalecamy, aby niestandardowe komponenty wejściowe wyprowadzać z InputBase<TValue>, chyba że uniemożliwiają to określone wymagania. Klasa InputBase<TValue> jest aktywnie utrzymywana przez zespół ASP.NET Core, zapewniając, że jest aktualna dzięki najnowszym Blazor funkcjom i zmianom struktury.
Komponent wprowadzania oparty na InputBase<T>
Poniższy przykładowy składnik:
- Dziedziczy po InputBase<TValue>. Komponenty dziedziczące po InputBase<TValue> muszą być używane w formularzu Blazor (EditForm).
- Pobiera dane wejściowe logiczne z pola wyboru.
- Ustawia kolor tła kontenera
<div>na podstawie stanu pola wyboru, co następuje, gdy po powiązaniu danych (@bind:after) wykonywana jest metodaAfterChange. - Należy przesłonić metodę
TryParseValueFromStringklasy bazowej, ale nie przetwarza ona danych wejściowych w postaci ciągu znaków, ponieważ pole wyboru nie dostarcza takich danych. Przykładowe implementacjeTryParseValueFromStringdla innych typów komponentów wejściowych, które przetwarzają dane wejściowe w postaci ciągu, są dostępne w kodzie źródłowym dokumentacji referencyjnej platformy ASP.NET Core.
Uwaga
Linki w dokumentacji do referencyjnego kodu źródłowego platformy .NET zwykle otwierają domyślną gałąź repozytorium, która odzwierciedla bieżący stan prac rozwojowych nad następną wersją platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).
EngineeringApprovalInputDerived.razor:
@using System.Diagnostics.CodeAnalysis
@inherits InputBase<bool>
<div class="@divCssClass">
<label>
Engineering Approval:
<input @bind="CurrentValue" @bind:after="AfterChange" class="@CssClass"
type="checkbox" />
</label>
</div>
@code {
private string? divCssClass;
private void AfterChange()
{
divCssClass = CurrentValue ? "bg-success text-white" : null;
}
protected override bool TryParseValueFromString(
string? value, out bool result,
[NotNullWhen(false)] out string? validationErrorMessage)
=> throw new NotSupportedException(
"This component does not parse string inputs. " +
$"Bind to the '{nameof(CurrentValue)}' property, " +
$"not '{nameof(CurrentValueAsString)}'.");
}
Aby użyć poprzedniego składnika w przykładowym formularzu przykładu starship (Starship3.razor/Starship.cs), zastąp blok <div> dla pola zatwierdzenia inżynieryjnego wystąpieniem składnika EngineeringApprovalInputDerived, powiązanym z właściwością IsValidatedDesign modelu:
- <div>
- <label>
- Engineering Approval:
- <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
- </label>
- </div>
+ <EngineeringApprovalInputDerived @bind-Value="Model!.IsValidatedDesign" />
Jeśli składnik dziedziczony z InputBase<TValue> jest zawsze renderowany statycznie, przypisz właściwość InputBase<TValue>.NameAttributeValue do atrybutu name elementów <input>:
<input @bind="CurrentValue" @bind:after="AfterChange" class="@CssClass"
type="checkbox" name="@NameAttributeValue" />
Powyższe przypisanie nie jest konieczne, jeśli składnik ma gwarancję, że zawsze jest renderowany interaktywnie.
Komponent do wprowadzania danych zapewniający programiście pełną kontrolę
Poniższy przykładowy składnik:
- Nie dziedziczy po InputBase<TValue>. Składnik przejmuje pełną kontrolę nad przetwarzaniem wejściowym, w tym powiązaniem, wywołaniami zwrotnymi i walidacją. Składnik może być używany wewnątrz lub na zewnątrz Blazor formularza (EditForm).
- Pobiera dane wejściowe logiczne z pola wyboru.
- Zmienia kolor tła, jeśli pole wyboru jest zaznaczone.
Kod w komponencie zawiera:
Właściwość
Valuejest używana z powiązaniem dwukierunkowym, aby uzyskać lub ustawić wartość danych wejściowych.ValueChangedto wywołanie zwrotne, które aktualizuje powiązaną wartość.W przypadku użycia w formularzu Blazor :
- EditContext jest wartością kaskadową.
-
fieldCssClassstylizuje pole na podstawie wyniku walidacji EditContext. -
ValueExpressionjest wyrażeniem (Expression<Func<T>>) przypisanym przez strukturę identyfikującą powiązaną wartość. -
FieldIdentifier unikatowo identyfikuje jedno pole, które można edytować, zwykle odpowiadające właściwości modelu. Identyfikator pola jest tworzony za pomocą wyrażenia identyfikującego powiązaną wartość (
ValueExpression).
W programie obsługi zdarzeń
OnChange:- Wartość pola wyboru jest pobierana z elementu InputFileChangeEventArgs.
- Ustawiono kolor tła i kolor tekstu elementu kontenera
<div>. - EventCallback.InvokeAsync wywołuje delegata skojarzonego z powiązaniem i wysyła do odbiorców powiadomienie o zdarzeniu informujące, że wartość uległa zmianie.
- Jeśli komponent jest używany w elemencie EditForm (właściwość
EditContextnie ma wartościnull), wywoływana jest metoda EditContext.NotifyFieldChanged, aby uruchomić walidację.
EngineeringApprovalInputStandalone.razor:
@using System.Globalization
@using System.Linq.Expressions
<div class="@divCssClass">
<label>
Engineering Approval:
<input class="@fieldCssClass" @onchange="OnChange" type="checkbox"
value="@Value" />
</label>
</div>
@code {
private string? divCssClass;
private FieldIdentifier fieldIdentifier;
private string? fieldCssClass => EditContext?.FieldCssClass(fieldIdentifier);
[CascadingParameter]
private EditContext? EditContext { get; set; }
[Parameter]
public bool? Value { get; set; }
[Parameter]
public EventCallback<bool> ValueChanged { get; set; }
[Parameter]
public Expression<Func<bool>>? ValueExpression { get; set; }
protected override void OnInitialized()
{
fieldIdentifier = FieldIdentifier.Create(ValueExpression!);
}
private async Task OnChange(ChangeEventArgs args)
{
BindConverter.TryConvertToBool(args.Value, CultureInfo.CurrentCulture,
out var value);
divCssClass = value ? "bg-success text-white" : null;
await ValueChanged.InvokeAsync(value);
EditContext?.NotifyFieldChanged(fieldIdentifier);
}
}
Aby skorzystać z poprzedniego składnika w przykładowym formularzu starship example form (Starship3.razor/Starship.cs), zastąp blok <div> pola zatwierdzenia inżynieryjnego instancją komponentu EngineeringApprovalInputStandalone powiązaną z właściwością modelu IsValidatedDesign:
- <div>
- <label>
- Engineering Approval:
- <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
- </label>
- </div>
+ <EngineeringApprovalInputStandalone @bind-Value="Model!.IsValidatedDesign" />
Składnik EngineeringApprovalInputStandalone działa również poza elementem EditForm:
<EngineeringApprovalInputStandalone @bind-Value="ValidDesign" />
<div>
<b>ValidDesign:</b> @ValidDesign
</div>
@code {
private bool ValidDesign { get; set; }
}
Przycisków
Przykład w tej sekcji jest oparty na formularzu Starfleet Starship Database (Starship3 składnik) sekcji Przykładowy formularz tego artykułu.
Dodaj następujące enum typy do aplikacji. Utwórz nowy plik do przechowywania lub dodaj go do Starship.cs pliku.
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 }
}
Nadaj klasie ComponentEnums dostęp dla:
-
Starshipmodel wStarship.cs(na przykładusing static ComponentEnums;). -
Starfleet Starship Databaseformularz (Starship3.razor) (na przykład@using static ComponentEnums).
Użyj InputRadio<TValue> składników ze składnikiem InputRadioGroup<TValue> , aby utworzyć grupę przycisków radiowych. W poniższym przykładzie właściwości są dodawane do Starship modelu opisanego w sekcji Przykładowy formularz artykułu Składniki wejściowe:
[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 Zaktualizuj formularz (Starship3składnik) sekcji Przykładowy formularz artykułu Składniki wejściowe. Dodaj komponenty, aby utworzyć:
- Grupa przycisków radiowych dla producenta statku.
- Zagnieżdżona grupa przycisków radiowych dla silnika oraz koloru statku.
Uwaga
Zagnieżdżone grupy przycisków radiowych nie są często używane w formularzach, ponieważ mogą one spowodować dezorganizowany układ kontrolek formularzy, które mogą mylić użytkowników. Istnieją jednak przypadki, w których mają one sens w projektowaniu interfejsu użytkownika, na przykład w poniższym przykładzie, który łączy rekomendacje dla dwóch pól wejściowych użytkownika: silnika statku i koloru statku. Formularz wymaga wybrania jednego silnika i jednego koloru. Układ formularza wykorzystuje zagnieżdżone InputRadioGroup<TValue>, aby zestawić rekomendacje dotyczące silnika i koloru. Jednak użytkownik może połączyć dowolny silnik z dowolnym kolorem, aby wysłać formularz.
Uwaga
Upewnij się, że ComponentEnums klasa jest dostępna dla składnika w następującym przykładzie:
@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>
Uwaga
Jeśli Name zostanie pominięty, komponenty InputRadio<TValue> są grupowane według ich najbliższego przodka.
Jeśli zaimplementowano powyższy kod znaczników Razor w składniku Starship3 w sekcji Przykładowy formularz artykułu Składniki wejściowe, zaktualizuj rejestrowanie w metodzie 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);
Podczas pracy z przyciskami radiowymi w formularzu powiązanie danych jest obsługiwane inaczej niż inne elementy, ponieważ przyciski radiowe są oceniane jako grupa. Wartość każdego przycisku radiowego jest stała, ale wartość grupy przycisków radiowych jest wartością wybranego przycisku radiowego. W poniższym przykładzie pokazano, jak:
- Obsługa powiązania danych dla grupy przycisków radiowych.
- Obsługa walidacji przy użyciu składnika niestandardowego 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;
}
}
}
Aby uzyskać więcej informacji na temat ogólnych parametrów typu (@typeparam), zobacz następujące artykuły:
- Razor informacje o składni dla ASP.NET Core
- składniki ASP.NET Core Razor
- Składniki z szablonami na platformie ASP.NET Core Blazor
Użyj następującego przykładowego modelu.
StarshipModel.cs:
using System.ComponentModel.DataAnnotations;
namespace BlazorServer80
{
public class Model
{
[Range(1, 5)]
public int Rating { get; set; }
}
}
RadioButtonExample Poniższy składnik używa poprzedniego InputRadio składnika do uzyskania i zweryfikowania oceny od użytkownika:
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");
}
}