ASP.NET binding dei moduli principali Blazor
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Questo articolo illustra come usare l'associazione nei Blazor moduli.
EditForm
/
EditContext
modello
Un EditForm oggetto crea un EditContext oggetto basato sull'oggetto assegnato come valore a catena per altri componenti nel form. Tiene EditContext traccia dei metadati relativi al processo di modifica, inclusi i campi modulo modificati e i messaggi di convalida correnti. L'assegnazione a un oggetto EditForm.Model o può EditForm.EditContext associare un modulo ai dati.
Associazione di modelli
Assegnazione a 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();
}
Nota
La maggior parte degli esempi di modelli di modulo di questo articolo associa moduli alle proprietà C#, ma è supportata anche l'associazione di campi C#.
Associazione di contesto
Assegnazione a 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);
}
}
Assegnare EditForm Se vengono assegnati entrambi, viene generato un errore di runtime.
Tipi supportati
L'associazione supporta:
- Tipi primitivi
- Raccolte
- Tipi complessi
- Tipi ricorsivi
- Tipi con costruttori
- Enumerazioni
È anche possibile usare gli attributi e [DataMember]
per personalizzare l'associazione [IgnoreDataMember]
di modelli. Usare questi attributi per rinominare le proprietà, ignorare le proprietà e contrassegnare le proprietà come richiesto.
Opzioni di associazione aggiuntive
Sono disponibili opzioni aggiuntive per l'associazione di modelli da RazorComponentsServiceOptions quando si chiama AddRazorComponents:
- MaxFormMappingCollectionSize: numero massimo di elementi consentiti in una raccolta di moduli.
- MaxFormMappingRecursionDepth: profondità massima consentita quando si esegue il mapping ricorsivo dei dati del modulo.
- MaxFormMappingErrorCount: numero massimo di errori consentiti durante il mapping dei dati del modulo.
- MaxFormMappingKeySize: dimensione massima del buffer usato per leggere le chiavi dei dati del modulo.
Di seguito vengono illustrati i valori predefiniti assegnati dal framework:
builder.Services.AddRazorComponents(options =>
{
options.FormMappingUseCurrentCulture = true;
options.MaxFormMappingCollectionSize = 1024;
options.MaxFormMappingErrorCount = 200;
options.MaxFormMappingKeySize = 1024 * 2;
options.MaxFormMappingRecursionDepth = 64;
}).AddInteractiveServerComponents();
Nomi dei moduli
Usare il FormName parametro per assegnare un nome di modulo. I nomi dei moduli devono essere univoci per associare i dati del modello. Il formato seguente è denominato RomulanAle
:
<EditForm ... FormName="RomulanAle" ...>
...
</EditForm>
Specificare un nome di modulo:
- È necessario per tutti i moduli inviati da componenti lato server sottoposti a rendering statico.
- Non è necessario per i moduli inviati da componenti di cui è stato eseguito il rendering interattivo, che include moduli nelle app e nei Blazor WebAssembly componenti con una modalità di rendering interattiva. È tuttavia consigliabile specificare un nome di modulo univoco per ogni modulo per evitare errori di pubblicazione dei moduli in fase di esecuzione se l'interattività viene mai eliminata per un modulo.
Il nome del modulo viene controllato solo quando il modulo viene inviato a un endpoint come richiesta HTTP POST tradizionale da un componente lato server sottoposto a rendering statico. Il framework non genera un'eccezione al momento del rendering di un modulo, ma solo nel momento in cui arriva un HTTP POST e non specifica un nome di modulo.
Esiste un ambito di modulo senza nome (stringa vuota) sopra il componente radice dell'app, che è sufficiente quando non sono presenti conflitti di nomi di modulo nell'app. Se sono possibili conflitti di nome modulo, ad esempio quando si include un modulo da una libreria e non si dispone di alcun controllo del nome del modulo utilizzato dallo sviluppatore della libreria, fornire un ambito di nome modulo con il FormMappingScope componente nel Blazor Web Appprogetto principale del .
Nell'esempio seguente il HelloFormFromLibrary
componente ha un form denominato Hello
e si trova in una libreria.
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;
}
Il componente seguente NamedFormsWithScope
usa il componente della HelloFormFromLibrary
libreria e ha anche un modulo denominato Hello
. Il FormMappingScope nome dell'ambito del componente è ParentContext
per tutti i moduli forniti dal HelloFormFromLibrary
componente. Anche se entrambi i moduli in questo esempio hanno il nome del modulo (Hello
), i nomi dei moduli non si scontrano e gli eventi vengono indirizzati al modulo corretto per gli eventi POST del modulo.
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;
}
Specificare un parametro dal modulo ([SupplyParameterFromForm]
)
L'attributo [SupplyParameterFromForm]
indica che il valore della proprietà associata deve essere fornito dai dati del modulo per il modulo. I dati nella richiesta che corrispondono al nome della proprietà sono associati alla proprietà . Input basati su InputBase<TValue>
genera nomi di valori di modulo che corrispondono ai nomi Blazor usati per l'associazione di modelli. A differenza delle proprietà dei parametri del componente ([Parameter]
), le proprietà annotate con [SupplyParameterFromForm]
non devono essere contrassegnate come public
.
È possibile specificare i parametri di associazione del modulo seguenti all'attributo [SupplyParameterFromForm]
:
- Name: ottiene o imposta il nome del parametro. Il nome viene utilizzato per determinare il prefisso da utilizzare per trovare le corrispondenze con i dati del modulo e decidere se il valore deve essere associato o meno.
- FormName: ottiene o imposta il nome del gestore. Il nome viene utilizzato per associare il parametro al formato in base al nome del modulo per decidere se il valore deve essere associato o meno.
Nell'esempio seguente vengono associati in modo indipendente due forme ai relativi modelli in base al nome del modulo.
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; }
}
}
Annidare e associare moduli
Le indicazioni seguenti illustrano come annidare e associare moduli figlio.
La classe dettagli spedizione seguente (ShipDetails
) contiene una descrizione e una lunghezza per una sottomaschera.
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; }
}
La classe seguente Ship
assegna un nome a un identificatore (Id
) e include i dettagli della spedizione.
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();
}
}
La sottomaschera seguente viene utilizzata per la modifica dei valori del ShipDetails
tipo. Questa operazione viene implementata ereditando Editor<T> nella parte superiore del componente.
Editor<T> garantisce che il componente figlio generi i nomi dei campi modulo corretti in base al modello (T
), dove T
nell'esempio seguente è 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>
Il form principale è associato alla Ship
classe . Il StarshipSubform
componente viene usato per modificare i dettagli della spedizione, associati come 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);
}
Inizializzare i dati del modulo con SSR statico
Quando un componente adotta SSR statico, il OnInitialized{Async}
metodo del ciclo di vita e il OnParametersSet{Async}
del ciclo di vita vengono attivati quando viene inizialmente eseguito il rendering del componente e in ogni modulo POST nel server. Per inizializzare i valori del modello di modulo, verificare se il modello dispone già di dati prima di assegnare nuovi valori del modello in OnParametersSet{Async}
, come illustrato nell'esempio seguente.
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; }
}
}
Scenari avanzati di errore di mapping dei moduli
Il framework crea un'istanza e popola l'oggetto FormMappingContext per una maschera, ovvero il contesto associato all'operazione di mapping di un modulo specificato. Ogni ambito di mapping (definito da un componente) crea FormMappingScopeun'istanza FormMappingContext di . Ogni volta che un chiede [SupplyParameterFromForm]
al contesto un valore, il framework popola FormMappingContext con il valore tentato ed eventuali errori di mapping.
Gli sviluppatori non devono interagire direttamente con FormMappingContext , perché è principalmente un'origine di dati per InputBase<TValue>, EditContexte altre implementazioni interne per mostrare gli errori di mapping come errori di convalida. Negli scenari personalizzati avanzati gli sviluppatori possono accedere FormMappingContext direttamente come oggetto [CascadingParameter]
per scrivere codice personalizzato che utilizza i valori tentati e gli errori di mapping.
Componenti di input personalizzati
Per scenari di elaborazione di input personalizzati, le sottosezioni seguenti illustrano i componenti di input personalizzati:
Componente di input basato su
InputBase<T>
: il componente eredita da InputBase<TValue>, che fornisce un'implementazione di base per l'associazione, i callback e la convalida. I componenti che ereditano da InputBase<TValue> devono essere utilizzati in un Blazor modulo (EditForm).Componente di input con controllo completo per sviluppatori: il componente assume il controllo completo dell'elaborazione dell'input. Il codice del componente deve gestire l'associazione, i callback e la convalida. Il componente può essere utilizzato all'interno o all'esterno di un Blazor form.
È consigliabile derivare i componenti di input personalizzati da InputBase<TValue> , a meno che non vengano evitati requisiti specifici. La InputBase<TValue> classe viene gestita attivamente dal team di ASP.NET Core, assicurandosi che rimanga aggiornata con le funzionalità e le modifiche del framework più recenti Blazor .
Componente di input basato su InputBase<T>
Componente di esempio seguente:
- Eredita dall'oggetto InputBase<TValue>. I componenti che ereditano da InputBase<TValue> devono essere utilizzati in un Blazor modulo (EditForm).
- Accetta l'input booleano da una casella di controllo.
- Imposta il colore di sfondo del contenitore
<div>
in base allo stato della casella di controllo, che si verifica quando il metodo viene eseguito dopo l'associazioneAfterChange
(@bind:after
). - È necessario per eseguire l'override del metodo della classe di
TryParseValueFromString
base, ma non elabora i dati di input della stringa perché una casella di controllo non fornisce dati stringa. Le implementazioni di esempio diTryParseValueFromString
per altri tipi di componenti di input che elaborano l'input della stringa sono disponibili nell'origine di riferimento ASP.NET Core.
Nota
I collegamenti della documentazione all'origine del riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la versione successiva di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Switch branches or tags. Per altre informazioni, vedere How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Come selezionare un tag di versione del codice sorgente di ASP.NET - 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)}'.");
}
Per usare il componente precedente nel modulo di esempio starship (Starship3.razor
/Starship.cs
), sostituire il <div>
blocco per il campo di approvazione della progettazione con un'istanza EngineeringApprovalInputDerived
del componente associata alla proprietà del IsValidatedDesign
modello:
- <div>
- <label>
- Engineering Approval:
- <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
- </label>
- </div>
+ <EngineeringApprovalInputDerived @bind-Value="Model!.IsValidatedDesign" />
Se viene eseguito il rendering statico del componente che eredita da InputBase<TValue>, assegnare la proprietà InputBase<TValue>.NameAttributeValue all'attributo name
degli elementi <input>
:
<input @bind="CurrentValue" @bind:after="AfterChange" class="@CssClass"
type="checkbox" name="@NameAttributeValue" />
L'assegnazione precedente non è necessaria se il componente viene sempre eseguito in modo interattivo.
Componente di input con controllo completo per sviluppatori
Componente di esempio seguente:
- Non eredita da InputBase<TValue>. Il componente acquisisce il controllo completo dell'elaborazione dell'input, tra cui associazione, callback e convalida. Il componente può essere utilizzato all'interno o all'esterno di un Blazor form (EditForm).
- Accetta l'input booleano da una casella di controllo.
- Modifica il colore di sfondo se la casella di controllo è selezionata.
Il codice nel componente include:
La
Value
proprietà viene utilizzata con l'associazione bidirezionale per ottenere o impostare il valore dell'input.ValueChanged
è il callback che aggiorna il valore associato.Se usato in un Blazor modulo:
- EditContext è un valore a catena.
-
fieldCssClass
stili il campo in base al risultato della EditContext convalida. -
ValueExpression
è un'espressione (Expression<Func<T>>
) assegnata dal framework che identifica il valore associato. -
FieldIdentifier identifica in modo univoco un singolo campo che può essere modificato, in genere corrispondente a una proprietà del modello. L'identificatore del campo viene creato con l'espressione che identifica il valore associato (
ValueExpression
).
OnChange
Nel gestore eventi:- Il valore dell'input della casella di controllo viene ottenuto da InputFileChangeEventArgs.
- Vengono impostati il colore di sfondo e il colore del testo dell'elemento contenitore
<div>
. - EventCallback.InvokeAsync richiama il delegato associato all'associazione e invia una notifica di evento ai consumer che il valore è stato modificato.
- Se il componente viene usato in un oggetto EditForm (la proprietà non
EditContext
è ),null
viene chiamato per attivare la EditContext.NotifyFieldChanged convalida.
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);
}
}
Per usare il componente precedente nel modulo di esempio starship (Starship3.razor
/Starship.cs
), sostituire il <div>
blocco per il campo di approvazione della progettazione con un'istanza EngineeringApprovalInputStandalone
del componente associata alla proprietà del IsValidatedDesign
modello:
- <div>
- <label>
- Engineering Approval:
- <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
- </label>
- </div>
+ <EngineeringApprovalInputStandalone @bind-Value="Model!.IsValidatedDesign" />
Il EngineeringApprovalInputStandalone
componente è anche funzionale all'esterno di un oggetto EditForm:
<EngineeringApprovalInputStandalone @bind-Value="ValidDesign" />
<div>
<b>ValidDesign:</b> @ValidDesign
</div>
@code {
private bool ValidDesign { get; set; }
}
Pulsanti di opzione
L'esempio in questa sezione si basa sul Starfleet Starship Database
modulo (Starship3
componente) della sezione Modulo di esempio di questo articolo.
Aggiungere i tipienum
all'app. Creare un nuovo file per memorizzarli o aggiungerli al Starship.cs
file.
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 }
}
Rendere la ComponentEnums
classe accessibile a:
-
Starship
modello inStarship.cs
(ad esempio,using static ComponentEnums;
). -
Starfleet Starship Database
form () (Starship3.razor
ad esempio,@using static ComponentEnums
).
Usare InputRadio<TValue> i componenti con il InputRadioGroup<TValue> componente per creare un gruppo di pulsanti di opzione. Nell'esempio seguente le proprietà vengono aggiunte al Starship
modello descritto nella sezione Modulo di esempio dell'articolo Componenti di input:
[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;
Aggiornare il Starfleet Starship Database
modulo (Starship3
componente) della sezione Modulo di esempio dell'articolo Componenti di input. Aggiungere i componenti da produrre:
- Gruppo di pulsanti di opzione per il produttore della nave.
- Gruppo di pulsanti di opzione annidati per il motore e il colore della nave.
Nota
I gruppi di pulsanti di opzione annidati non vengono spesso usati nei moduli perché possono comportare un layout disorganizzato dei controlli modulo che possono confondere gli utenti. Tuttavia, esistono casi in cui hanno senso nella progettazione dell'interfaccia utente, ad esempio nell'esempio seguente che associa raccomandazioni per due input utente, motore di spedizione e colore spedizione. Un motore e un colore sono richiesti dalla convalida del modulo. Il layout del modulo usa s annidati InputRadioGroup<TValue>per associare le raccomandazioni relative al motore e ai colori. Tuttavia, l'utente può combinare qualsiasi motore con qualsiasi colore per inviare il modulo.
Nota
Assicurarsi di rendere disponibile la ComponentEnums
classe per il componente per l'esempio seguente:
@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>
Nota
Se Name
viene omesso, InputRadio<TValue> i componenti vengono raggruppati in base al predecessore più recente.
Se il markup precedente Razor è stato implementato nel Starship3
componente della sezione Modulo di esempio dell'articolo Componenti di input, aggiornare la registrazione per il Submit
metodo :
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);
Quando si usano pulsanti di opzione in un modulo, il data binding viene gestito in modo diverso rispetto ad altri elementi perché i pulsanti di opzione vengono valutati come gruppo. Il valore di ogni pulsante di opzione è fisso, ma il valore del gruppo di pulsanti di opzione è il valore del pulsante di opzione selezionato. L'esempio seguente illustra come:
- Gestire il data binding per un gruppo di pulsanti di opzione.
- Supportare la convalida usando un componente personalizzato 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;
}
}
}
Per altre informazioni sui parametri di tipo generico (@typeparam
), vedere gli articoli seguenti:
- Guida di riferimento della sintassi Razor per ASP.NET Core
- componenti di Razor base ASP.NET
- Componenti basati su modelli di ASP.NET Core Blazor
Usare il modello di esempio seguente.
StarshipModel.cs
:
using System.ComponentModel.DataAnnotations;
namespace BlazorServer80
{
public class Model
{
[Range(1, 5)]
public int Rating { get; set; }
}
}
Il componente seguente RadioButtonExample
usa il componente precedente InputRadio
per ottenere e convalidare una classificazione dall'utente:
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");
}
}