Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 10-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der .NET- und .NET Core-Supportrichtlinie. Die aktuelle Version finden Sie in der .NET 10-Version dieses Artikels.
In diesem Artikel wird erläutert, wie die Bindung in Blazor-Formularen verwendet wird.
EditForm
/
EditContext Modell
EditForm erstellt einen EditContext auf Grundlage des zugewiesenen Objekts als kaskadierenden Wert für andere Komponenten im Formular. Der EditContext verfolgt Metadaten über den Bearbeitungsprozess nach, einschließlich der Formularfelder, die geändert wurden, und der aktuellen Validierungsnachrichten. Durch das Zuweisen zu einem EditForm.Model oder einem EditForm.EditContext lässt sich ein Formular an Daten binden.
Modellbindung
Zuweisung zu 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();
}
Hinweis
Die meisten Formularmodellbeispielen dieses Artikels binden Formulare an C#-Eigenschaften, die C#-Feldbindung wird jedoch ebenfalls unterstützt.
Wenn dem Model Parameter EditFormeine andere Objektinstanz zugewiesen ist, erstellt das Formular ein neues EditContext. Der neue Kontext beginnt ohne geänderte Felder oder Überprüfungsmeldungen.
Kontextbindung
Zuweisung zu 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);
}
}
Weisen Sie einer EditForm-Klasse entweder eine EditContext-Eigenschaft oder ein Model zu. Wenn beide zugewiesen sind, wird ein Laufzeitfehler ausgelöst.
Unterstützte Typen
Die Bindung unterstützt Folgendes:
- Primitive Typen
- Sammlungen
- Komplexe Typen
- Rekursive Typen
- Typen mit Konstruktoren
- Enumerationen
Sie können auch die Attribute [DataMember] und [IgnoreDataMember] verwenden, um die Modellbindung anzupassen. Verwenden Sie diese Attribute, um Eigenschaften nach Bedarf umzubenennen, zu ignorieren und zu markieren.
Beim Binden eines Typs mit Konstruktorparametern hat der Konstruktorparameter Vorrang, wenn ein Konstruktorparameter einer Eigenschaft anhand des Namens entspricht. Der Mapper verwendet das explizite DataMember.Name der Eigenschaft, sofern vorhanden, als Namen des Formularfelds, ignoriert aber andernfalls die Zuordnungsattribute der Eigenschaft. Konstruktorparameter sind immer erforderlich.
Zusätzliche Bindungsoptionen
Zusätzliche Modellbindungsoptionen stehen in RazorComponentsServiceOptions zur Verfügung, wenn AddRazorComponents aufgerufen wird:
- MaxFormMappingCollectionSize: Maximale Anzahl der in einer Formularsammlung zulässigen Elemente.
- MaxFormMappingRecursionDepth: Maximal zulässige Tiefe, wenn Formulardaten rekursiv zugeordnet werden.
- MaxFormMappingErrorCount: Maximal zulässige Anzahl von Fehlern beim Zuordnen von Formulardaten.
- MaxFormMappingKeySize: Maximale Größe des Puffers, der zum Lesen von Formulardatenschlüsseln verwendet wird.
Im Folgenden werden die vom Framework zugewiesenen Standardwerte veranschaulicht:
builder.Services.AddRazorComponents(options =>
{
options.FormMappingUseCurrentCulture = true;
options.MaxFormMappingCollectionSize = 1024;
options.MaxFormMappingErrorCount = 200;
options.MaxFormMappingKeySize = 1024 * 2;
options.MaxFormMappingRecursionDepth = 64;
}).AddInteractiveServerComponents();
Formularnamen
Verwenden Sie den Parameter FormName, um einen Formularnamen zuzuweisen. Formularnamen müssen eindeutig sein, um Modelldaten zu binden. Das folgende Formular heißt RomulanAle:
<EditForm ... FormName="RomulanAle" ...>
...
</EditForm>
Formularnamen angeben:
- Ist für alle Formulare erforderlich, die von statisch gerenderten serverseitigen Komponenten übermittelt werden.
- Ist nicht erforderlich für Formulare, die von interaktiv gerenderten Komponenten übermittelt werden, die Formulare in Blazor WebAssembly-Apps und Komponenten mit einem interaktiven Rendermodus enthalten. Es wird jedoch empfohlen, für jedes Formular einen eindeutigen Formularnamen anzugeben, um Formularveröffentlichungsfehler zur Laufzeit zu verhindern, wenn die Interaktivität für ein Formular verworfen wird.
Der Formularname wird nur überprüft, wenn das Formular als herkömmliche HTTP POST-Anforderung von einer statisch gerenderten serverseitigen Komponente an einen Endpunkt übermittelt wird. Das Framework löst eine Ausnahme nicht zum Zeitpunkt des Renderns eines Formulars, sondern erst zu dem Zeitpunkt aus, an dem eine HTTP POST-Anforderung eintrifft. Es gibt keinen Formularnamen an.
Es gibt einen unbenannten (leere Zeichenfolge) Formularbereich oberhalb der Stammkomponente der App, der ausreicht, wenn es in der App keine Kollisionen mit Formularnamen gibt. Wenn Konflikte bei Formularnamen möglich sind, z. B. wenn Sie ein Formular aus einer Bibliothek einbinden und keinen Einfluss auf den vom Entwickler der Bibliothek verwendeten Formularnamen haben, geben Sie mit der Komponente FormMappingScope im Hauptprojekt von Blazor Web App einen Namensbereich für Formularnamen an.
Im folgenden Beispiel hat die HelloFormFromLibrary-Komponente ein Formular namens Hello und befindet sich in einer Bibliothek.
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;
}
Die folgende NamedFormsWithScope-Komponente verwendet die HelloFormFromLibrary-Komponente der Bibliothek, und sie verfügt über ein Formular mit dem Namen Hello. Der Bereichsname der FormMappingScope-Komponente lautet ParentContext für alle Formulare, die von der HelloFormFromLibrary-Komponente bereitgestellt werden. Obwohl beide Formulare in diesem Beispiel denselben Formularnamen aufweisen (Hello), tritt kein Konflikt bei den Formularnamen auf, und die Ereignisse werden für POST-Ereignisse an das richtige Formular weitergeleitet.
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;
}
Angeben eines Parameters aus dem Formular ([SupplyParameterFromForm])
Das Attribut [SupplyParameterFromForm] gibt an, dass der Wert der zugeordneten Eigenschaft aus den Formulardaten für das Formular bereitgestellt werden soll. Daten in der Anforderung, die dem Namen der Eigenschaft entsprechen, werden an die Eigenschaft gebunden. Auf InputBase<TValue> basierende Eingaben generieren Formularwertnamen, die den Namen entsprechen, die Blazor für die Modellbindung verwendet. Im Gegensatz zu den Eigenschaften von Komponentenparametern ([Parameter]) ist es bei den mit [SupplyParameterFromForm] kommentierten Eigenschaften nicht erforderlich, sie mit public zu kennzeichnen.
Blazor Die Formularzuordnung mit [SupplyParameterFromForm] verwendet nicht die MVC-Modellbindung. Attribute im Microsoft.AspNetCore.Mvc.ModelBinding-Namespace, wie [BindNever] und [BindRequired], werden nicht unterstützt. Verwenden Sie diese Attribute nicht, um Overposting zu verhindern. Verwenden Sie stattdessen ein dediziertes Formularmodell, ein Ansichtsmodell oder ein DTO-Objekt (Data Transfer Object), das nur die Eigenschaften enthält, die Benutzer ändern dürfen. Weitere Informationen finden Sie unter "Minimieren von Überpostungsangriffen".
Sie können die folgenden Formularbindungsparameter für das [SupplyParameterFromForm]-Attribut angeben:
- Name: Ruft den Namen für den Parameter ab oder legt ihn fest. Der Name wird verwendet, um das Präfix zu bestimmen, das für den Abgleich mit den Formulardaten verwendet werden soll, und um zu entscheiden, ob der Wert gebunden werden muss.
- FormName: Ruft den Namen für den Handler ab oder legt diesen fest. Der Name wird für den Abgleich des Parameters mit dem Formular anhand des Formularnamens verwendet, um zu entscheiden, ob der Wert gebunden werden muss.
Das folgende Beispiel bindet zwei Formulare unabhängig voneinander anhand des Formularnamens an ihre Modelle.
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; }
}
}
Formulare verschachteln und verknüpfen
Die folgende Anleitung veranschaulicht, wie untergeordnete Formulare geschachtelt und gebunden werden.
Die folgende Klasse für Schiffdetails (ShipDetails) enthält eine Beschreibung und die Länge eines Unterformulars.
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; }
}
Die folgende Ship-Klasse benennt einen Bezeichner (Id) und enthält die Schiffsdetails.
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();
}
}
Das folgende Unterformular wird zum Bearbeiten von Werten vom Typ ShipDetails verwendet. Dies wird durch Vererben von Editor<T> oben in der Komponente implementiert.
Editor<T> stellt sicher, dass die untergeordnete Komponente die richtigen Formularfeldnamen basierend auf dem Modell (T) generiert, wobei T im folgenden Beispiel ShipDetails lautet.
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>
Das Hauptformular ist an die Ship-Klasse gebunden. Die Komponente StarshipSubform wird verwendet, um Lieferdetails zu bearbeiten, die als Model!.Details gebunden sind.
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);
}
Formulardaten mit statischem SSR initialisieren
Wenn eine Komponente statisches SSR verwendet, werden die OnInitialized{Async}-Lebenszyklus-Methode und die OnParametersSet{Async}-Lebenszyklus-Methode beim ersten Rendern der Komponente und bei jedem POST-Vorgang des Formulars an den Server ausgelöst. Um die Werte des Formularmodells zu initialisieren, überprüfen Sie, ob das Modell bereits über Daten verfügt, bevor Sie neue Modellwerte in OnParametersSet{Async} zuweisen, wie im folgenden Beispiel gezeigt.
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; }
}
}
Erweiterte Fehlerszenarien bei der Formularzuordnung
Das Framework instanziiert den FormMappingContext für ein Formular und füllt ihn auf. Dies ist der Kontext, der mit dem Zuordnungsvorgang eines bestimmten Formulars verknüpft ist. Jeder Zuordnungsbereich (definiert durch eine FormMappingScope-Komponente) instanziiert FormMappingContext. Jedes Mal, wenn ein [SupplyParameterFromForm] den Kontext nach einem Wert abfragt, füllt das Framework den FormMappingContext mit dem versuchten Wert und allen Zuordnungsfehlern auf.
Entwickler*innen interagieren wahrscheinlich nicht direkt mit FormMappingContext, da es sich hauptsächlich um eine Datenquelle für InputBase<TValue>, EditContext und andere interne Implementierungen handelt, um Zuordnungsfehler als Validierungsfehler anzuzeigen. In fortgeschrittenen benutzerdefinierten Szenarien können Entwickler*innen direkt auf FormMappingContext als [CascadingParameter] zugreifen, um benutzerdefinierten Code zu schreiben, der die versuchten Werte und Zuordnungsfehler verarbeitet.
InputText basierend auf dem Eingabeereignis
Verwenden Sie die InputText-Komponente, um eine benutzerdefinierte Komponente zu erstellen, die das oninput-Ereignis (input) anstelle des onchange-Ereignisses (change) nutzt. Die Verwendung des input-Ereignisses löst die Feldvalidierung bei jeder Tastatureingabe aus.
Die folgende CustomInputText-Komponente erbt die InputText-Komponente des Frameworks und legt die Ereignisbindung auf das oninput-Ereignis (input) fest.
CustomInputText.razor:
@inherits InputText
<input @attributes="AdditionalAttributes"
class="@CssClass"
@bind="CurrentValueAsString"
@bind:event="oninput" />
Die CustomInputText-Komponente kann überall dort verwendet werden, wo InputText verwendet wird. Die folgende Komponente verwendet die gemeinsam genutzte CustomInputText-Komponente.
Starship11.razor:
@page "/starship-11"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship11> Logger
<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship11">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label>
Identifier:
<CustomInputText @bind-Value="Model!.Id" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
<div>
CurrentValue: @Model?.Id
</div>
@code {
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
private void Submit() => Logger.LogInformation("Submit: Processing form");
public class Starship
{
[Required]
[StringLength(10, ErrorMessage = "Id is too long.")]
public string? Id { get; set; }
}
}
@page "/starship-11"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship11> Logger
<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship11">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label>
Identifier:
<CustomInputText @bind-Value="Model!.Id" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
<div>
CurrentValue: @Model?.Id
</div>
@code {
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
private void Submit() => Logger.LogInformation("Submit: Processing form");
public class Starship
{
[Required]
[StringLength(10, ErrorMessage = "Id is too long.")]
public string? Id { get; set; }
}
}
@page "/starship-11"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship11> Logger
<EditForm Model="Model" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<ValidationSummary />
<CustomInputText @bind-Value="Model!.Id" />
<button type="submit">Submit</button>
</EditForm>
<div>
CurrentValue: @Model?.Id
</div>
@code {
public Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
private void Submit()
{
Logger.LogInformation("Submit called: Processing the form");
}
public class Starship
{
[Required]
[StringLength(10, ErrorMessage = "Id is too long.")]
public string? Id { get; set; }
}
}
Benutzerdefinierte Eingabekomponenten
Für benutzerdefinierte Eingabeverarbeitungsszenarien werden in den folgenden Unterabschnitten benutzerdefinierte Eingabekomponenten vorgestellt:
Eingabekomponente basierend auf
InputBase<T>: Die Komponente erbt von InputBase<TValue>, das eine Basisimplementierung für das Verknüpfen, Rückrufe und die Validierung bereitstellt. Komponenten, die von InputBase<TValue> erben, müssen in einer Blazor-Form (EditForm) verwendet werden.Eingabekomponente mit voller Kontrolle durch die Entwickler*in: Die Komponente übernimmt die volle Kontrolle über die Eingabeverarbeitung. Der Code der Komponente muss das Verknüpfen, die Rückrufe und die Validierung verwalten. Die Komponente kann innerhalb oder außerhalb einer Blazor-Form verwendet werden.
Es wird empfohlen, ihre benutzerdefinierten Eingabekomponenten von InputBase<TValue> abzuleiten, es sei denn, bestimmte Anforderungen verhindern dies. Die InputBase<TValue>-Klasse wird aktiv vom ASP.NET Core-Team verwaltet, um sicherzustellen, dass sie mit den neuesten Blazor-Features und Frameworkänderungen auf dem neuesten Stand bleibt.
Eingabekomponente basierend auf InputBase<T>
Die folgende Beispielkomponente:
- Erbt von InputBase<TValue>. Komponenten, die von InputBase<TValue> erben, müssen in einer Blazor-Form (EditForm) verwendet werden.
- Akzeptiert boolesche Eingaben von einem Kontrollkästchen.
- Legt die Hintergrundfarbe seines Containers
<div>auf der Grundlage des Zustands des Kontrollkästchens fest, der auftritt, wenn die MethodeAfterChangenach dem Verknüpfen ausgeführt wird (@bind:after). - Ist erforderlich, um die
TryParseValueFromString-Methode der Basisklasse zu überschreiben, verarbeitet aber keine Zeichenfolge-Eingabedaten, da ein Ankreuzfeld keine Zeichenfolge-Daten bereitstellt. Beispielimplementierungen vonTryParseValueFromStringfür andere Arten von Eingabekomponenten, die Zeichenfolgen verarbeiten, sind in der ASP.NET Core-Referenzquelle verfügbar.
Hinweis
Dokumentationslinks zur .NET-Referenzquelle laden in der Regel den Standardbranch des Repositorys, der die aktuelle Entwicklung für das nächste Release von .NET darstellt. Um ein Tag für ein bestimmtes Release auszuwählen, wählen Sie diesen mit der Dropdownliste Switch branches or tags (Branches oder Tags wechseln) aus.
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)}'.");
}
Um die vorangehende Komponente in der Starship-Beispielform (Starship3.razor/Starship.cs) zu verwenden, ersetzen Sie den <div>-Block für das technische Genehmigungsfeld durch eine EngineeringApprovalInputDerived-Komponenteninstanz, die mit der IsValidatedDesign-Eigenschaft des Modells verknüpft ist:
- <div>
- <label>
- Engineering Approval:
- <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
- </label>
- </div>
+ <EngineeringApprovalInputDerived @bind-Value="Model!.IsValidatedDesign" />
Wenn die Komponente, die von InputBase<TValue> erbt, jemals statisch gerendert wird, weisen Sie die InputBase<TValue>.NameAttributeValue-Eigenschaft dem name-Attribut von <input>-Elementen zu:
<input @bind="CurrentValue" @bind:after="AfterChange" class="@CssClass"
type="checkbox" name="@NameAttributeValue" />
Die vorhergehende Zuweisung ist nicht notwendig, wenn die Komponente garantiert immer interaktiv gerendert wird.
Eingabekomponente mit vollständiger Entwicklersteuerung
Die folgende Beispielkomponente:
- Erbt nicht von InputBase<TValue>. Die Komponente übernimmt die vollständige Kontrolle über die Eingabeverarbeitung, einschließlich der Verknüpfung, der Rückrufe und der Validierung. Die Komponente kann innerhalb oder außerhalb einer Blazor-Form (EditForm) verwendet werden.
- Akzeptiert boolesche Eingaben von einem Kontrollkästchen.
- Ändert die Hintergrundfarbe, wenn das Kontrollkästchen angekreuzt wurde.
Der Code der Komponente enthält:
Die Eigenschaft
Valuewird bei der zweiseitigen Verknüpfung verwendet, um den Wert der Eingabe zu erhalten oder festzulegen.ValueChangedist der Callback, der den verknüpften Wert aktualisiert.Bei Verwendung in einer Blazor-Form:
- Das EditContext ist ein kaskadierender Wert.
-
fieldCssClassformatiert das Feld auf der Grundlage des Ergebnisses der EditContext-Überprüfung. -
ValueExpressionist ein Ausdruck (Expression<Func<T>>), der vom Framework zugewiesen wird, der den gebundenen Wert identifiziert. -
FieldIdentifier identifiziert eindeutig ein einzelnes Feld, das bearbeitet werden kann und normalerweise einer Modelleigenschaft entspricht. Der Feldbezeichner wird mit dem Ausdruck erstellt, der den verknüpften Wert identifiziert (
ValueExpression).
Im
OnChange-Ereignishandler:- Der Wert der Checkbox-Eingabe ergibt sich aus InputFileChangeEventArgs.
- Die Hintergrundfarbe und die Textfarbe des Container-Elements
<div>werden festgelegt. - EventCallback.InvokeAsync ruft den mit der Bindung verknüpften Delegaten auf und sendet eine Ereignisbenachrichtigung an die Konsumenten darüber, dass sich der Wert geändert hat.
- Wenn die Komponente in einem EditForm verwendet wird (die
EditContext-Eigenschaft ist nichtnull), wird EditContext.NotifyFieldChanged aufgerufen, um die Validierung auszulösen.
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);
}
}
Um die vorangehende Komponente im Sternenschiff-Beispielformular (Starship3.razor/Starship.cs) zu verwenden, ersetzen Sie den <div>-Block für das technische Genehmigungsfeld durch eine EngineeringApprovalInputStandalone-Komponenteninstanz, die mit der IsValidatedDesign-Eigenschaft des Modells verknüpft ist:
- <div>
- <label>
- Engineering Approval:
- <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
- </label>
- </div>
+ <EngineeringApprovalInputStandalone @bind-Value="Model!.IsValidatedDesign" />
Die EngineeringApprovalInputStandalone-Komponente hat auch außerhalb eines EditForm eine Funktion:
<EngineeringApprovalInputStandalone @bind-Value="ValidDesign" />
<div>
<b>ValidDesign:</b> @ValidDesign
</div>
@code {
private bool ValidDesign { get; set; }
}
Optionsfelder
Das Beispiel in diesem Abschnitt basiert auf dem Starfleet Starship Database-Formular (Starship3-Komponente) des Abschnitts Beispielformular in diesem Artikel.
Fügen Sie der App die folgenden enum-Typen hinzu. Erstellen Sie eine neue Datei, um diese aufzunehmen, oder fügen Sie sie der Datei Starship.cs hinzu.
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 }
}
Machen Sie die ComponentEnums-Klasse für Folgendes zugänglich:
-
Starship-Modell inStarship.cs(z. B.using static ComponentEnums;). -
Starfleet Starship Database-Formular (Starship3.razor) (z. B.@using static ComponentEnums).
Verwenden Sie InputRadio<TValue>-Komponenten mit der InputRadioGroup<TValue>-Komponente, um eine Optionsfeldgruppe zu erstellen. Im folgenden Beispiel werden dem Starship-Modell Eigenschaften hinzugefügt, das im Abschnitt Beispielformular des Artikels Eingabekomponenten beschrieben wird:
[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;
Aktualisieren Sie das Starfleet Starship Database-Formular (Starship3-Komponente) im Abschnitt Beispielformular des Artikels Eingabekomponenten. Fügen Sie die Komponenten hinzu, damit Folgendes erstellt wird:
- Eine Optionsfeldgruppe für den Schiffshersteller.
- Eine geschachtelte Optionsfeldgruppe für den Motor und die Farbe des Schiffs.
Hinweis
Geschachtelte Optionsfeldgruppen werden nicht häufig in Formularen verwendet, weil sie zu einem unorganisierten Layout von Formularsteuerelementen führen können, das Benutzer verwirren kann. Es gibt jedoch Fälle, in denen sie im Benutzeroberflächenentwurf sinnvoll sind, z. B. im folgenden Beispiel, bei dem Empfehlungen für zwei Benutzereingaben (Schiffsmotor (ship enginge) und Schiffsfarbe (ship color)) gepaart werden. Für die Validierung des Formulars ist ein Motor und eine Farbe erforderlich. Das Layout des Formulars verwendet geschachtelte InputRadioGroup<TValue>s, um Empfehlungen für Motor und Farbe zu paaren. Der Nutzer kann jedoch jede Engine mit jeder Farbe kombinieren, um das Formular abzusenden.
Hinweis
Stellen Sie sicher, dass die ComponentEnums-Klasse für die Komponente für das folgende Beispiel verfügbar ist:
@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>
Hinweis
Wenn Name ausgelassen wird, werden die InputRadio<TValue>-Komponenten nach dem direkten Vorgänger gruppiert.
Wenn Sie das vorangehende Razor-Markup in der Starship3-Komponente des Abschnitts Beispielformular des Artikels Eingabekomponenten implementiert haben, aktualisieren Sie die Protokollierung für die Submit-Methode:
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);
Beim Verwenden von Optionsfeldern in einem Formular werden Datenbindungen nicht wie andere Elemente verarbeitet, da Optionsfelder als Gruppe ausgewertet werden. Der Wert der einzelnen Optionsfelder ist fest. Der Wert der Optionsfeldgruppe ist jedoch der Wert des ausgewählten Optionsfelds. Das folgende Beispiel veranschaulicht die Vorgehensweise:
- Verarbeiten von Datenbindungen für eine Optionsfeldgruppe
- Unterstützen der Validierung mithilfe einer benutzerdefinierten InputRadio<TValue>-Komponente
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;
}
}
}
Weitere Informationen zu den generischen Typparametern (@typeparam) finden Sie in den folgenden Artikeln:
- Razor-Syntaxreferenz für ASP.NET Core
- ASP.NET Core-RazorKomponenten
- vorlagenbasierte Blazor Komponenten in ASP.NET Core
Verwenden Sie das folgende Beispielmodell.
StarshipModel.cs:
using System.ComponentModel.DataAnnotations;
namespace BlazorServer80
{
public class Model
{
[Range(1, 5)]
public int Rating { get; set; }
}
}
Die folgende RadioButtonExample-Komponente verwendet die vorangehende InputRadio-Komponente, um eine Bewertung vom Benutzer zu erhalten und sie zu überprüfen:
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");
}
}