ASP.NET Core Blazor-DatenbindungASP.NET Core Blazor data binding
Von Luke Latham, Daniel Roth und Steve SandersonBy Luke Latham, Daniel Roth, and Steve Sanderson
Razor-Komponenten stellen Features zur Datenbindung über ein HTML-Elementattribut namens @bind
bereit, mit einem Feld, einer Eigenschaft oder einem Razor-Ausdruckswert.Razor components provide data binding features via an HTML element attribute named @bind
with a field, property, or Razor expression value.
Im folgenden Beispiel wird ein <input>
-Element an das currentValue
-Feld und ein <input>
-Element an die CurrentValue
-Eigenschaft gebunden:The following example binds an <input>
element to the currentValue
field and an <input>
element to the CurrentValue
property:
<p>
<input @bind="currentValue" /> Current value: @currentValue
</p>
<p>
<input @bind="CurrentValue" /> Current value: @CurrentValue
</p>
@code {
private string currentValue;
private string CurrentValue { get; set; }
}
Wenn eines der Elemente den Fokus verliert, wird das gebundene Feld oder die Eigenschaft aktualisiert.When one of the elements loses focus, its bound field or property is updated.
Das Textfeld wird in der Benutzeroberfläche nur dann aktualisiert, wenn die Komponente gerendert wird, nicht als Reaktion auf die Änderung des Werts des Felds oder der Eigenschaft.The text box is updated in the UI only when the component is rendered, not in response to changing the field's or property's value. Da sich Komponenten nach der Ausführung von Ereignishandlercode selbst rendern, werden Feld- und Eigenschaftsaktualisierungen in der Regel unmittelbar nach dem Auslösen eines Ereignishandlers in der Benutzeroberfläche widergespiegelt.Since components render themselves after event handler code executes, field and property updates are usually reflected in the UI immediately after an event handler is triggered.
Die Verwendung von @bind
mit der CurrentValue
-Eigenschaft (<input @bind="CurrentValue" />
) entspricht im Wesentlichen dem Folgenden:Using @bind
with the CurrentValue
property (<input @bind="CurrentValue" />
) is essentially equivalent to the following:
<input value="@CurrentValue"
@onchange="@((ChangeEventArgs __e) => CurrentValue =
__e.Value.ToString())" />
@code {
private string CurrentValue { get; set; }
}
Wenn die Komponente gerendert wird, stammt der value
des Eingabeelements aus der CurrentValue
-Eigenschaft.When the component is rendered, the value
of the input element comes from the CurrentValue
property. Wenn der Benutzer in das Textfeld eingibt und den Elementfokus ändert, wird das Ereignis onchange
ausgelöst und die Eigenschaft CurrentValue
auf den geänderten Wert festgelegt.When the user types in the text box and changes element focus, the onchange
event is fired and the CurrentValue
property is set to the changed value. In Wirklichkeit ist die Codegenerierung komplexer, weil @bind
Fälle behandelt, in denen Typkonvertierungen durchgeführt werden.In reality, the code generation is more complex than that because @bind
handles cases where type conversions are performed. Im Prinzip assoziiert @bind
den aktuellen Wert eines Ausdrucks mit einem value
-Attribut und behandelt Änderungen mit dem registrierten Handler.In principle, @bind
associates the current value of an expression with a value
attribute and handles changes using the registered handler.
Binden Sie eine Eigenschaft oder ein Feld an andere Ereignisse, indem Sie auch ein @bind:event
-Attribut mit einem event
-Parameter einbeziehen.Bind a property or field on other events by also including an @bind:event
attribute with an event
parameter. Das folgende Beispiel bindet die Eigenschaft CurrentValue
an das Ereignis oninput
:The following example binds the CurrentValue
property on the oninput
event:
<input @bind="CurrentValue" @bind:event="oninput" />
@code {
private string CurrentValue { get; set; }
}
Im Gegensatz zu onchange
, das ausgelöst wird, wenn das Element den Fokus verliert, wird oninput
ausgelöst, wenn sich der Wert des Textfelds ändert.Unlike onchange
, which fires when the element loses focus, oninput
fires when the value of the text box changes.
Bei der Attributbindung wird die Groß- und Kleinschreibung berücksichtigt.Attribute binding is case sensitive:
@bind
ist gültig.@bind
is valid.@Bind
und@BIND
sind ungültig.@Bind
and@BIND
are invalid.
Nicht analysierbare WerteUnparsable values
Wenn ein Benutzer einem Element mit Datenbindung einen nicht analysierbaren Wert zur Verfügung stellt, wird der nicht analysierbare Wert automatisch auf seinen vorherigen Wert zurückgesetzt, wenn das Bindungsereignis ausgelöst wird.When a user provides an unparsable value to a databound element, the unparsable value is automatically reverted to its previous value when the bind event is triggered.
Betrachten Sie das folgende Szenario:Consider the following scenario:
Ein
<input>
-Element ist an einenint
-Typ mit einem Anfangswert von123
gebunden:An<input>
element is bound to anint
type with an initial value of123
:<input @bind="inputValue" /> @code { private int inputValue = 123; }
Der Benutzer aktualisiert den Wert des Elements auf der Seite zu
123.45
und ändert den Elementfokus.The user updates the value of the element to123.45
in the page and changes the element focus.
Im vorangehenden Szenario wird der Wert des Elements auf 123
zurückgesetzt.In the preceding scenario, the element's value is reverted to 123
. Wenn der Wert 123.45
zugunsten des ursprünglichen Werts von 123
abgelehnt wird, versteht der Benutzer, dass sein Wert nicht akzeptiert wurde.When the value 123.45
is rejected in favor of the original value of 123
, the user understands that their value wasn't accepted.
Standardmäßig gilt die Bindung für das onchange
-Ereignis des Elements (@bind="{PROPERTY OR FIELD}"
).By default, binding applies to the element's onchange
event (@bind="{PROPERTY OR FIELD}"
). Verwenden Sie @bind="{PROPERTY OR FIELD}" @bind:event={EVENT}
, um die Bindung bei einem anderen Ereignis auszulösen.Use @bind="{PROPERTY OR FIELD}" @bind:event={EVENT}
to trigger binding on a different event. Für das oninput
-Ereignis (@bind:event="oninput"
) erfolgt die Umkehrung nach jedem Tastendruck, der einen nicht analysierbaren Wert einführt.For the oninput
event (@bind:event="oninput"
), the reversion occurs after any keystroke that introduces an unparsable value. Wenn das oninput
-Ereignis mit einem int
-gebundenen Typ angestrebt wird, wird ein Benutzer daran gehindert, ein .
-Zeichen einzugeben.When targeting the oninput
event with an int
-bound type, a user is prevented from typing a .
character. Ein .
-Zeichen wird sofort entfernt, sodass der Benutzer sofort die Rückmeldung erhält, dass nur ganze Zahlen zulässig sind.A .
character is immediately removed, so the user receives immediate feedback that only whole numbers are permitted. Es gibt Szenarien, in denen die Umkehrung des Werts auf das oninput
Ereignis nicht ideal ist, z. B. wenn dem Benutzer erlaubt werden soll, einen nicht analysierbaren <input>
-Wert zu löschen.There are scenarios where reverting the value on the oninput
event isn't ideal, such as when the user should be allowed to clear an unparsable <input>
value. Zu den Alternativen gehören:Alternatives include:
- Verwenden Sie nicht das Ereignis
oninput
.Don't use theoninput
event. Verwenden Sie das Standardereignisonchange
(geben Sie nur@bind="{PROPERTY OR FIELD}"
an), bei dem ein ungültiger Wert erst dann rückgängig gemacht wird, wenn das Element den Fokus verliert.Use the defaultonchange
event (only specify@bind="{PROPERTY OR FIELD}"
), where an invalid value isn't reverted until the element loses focus. - Binden Sie an einen Nullable-Typ, z. B.
int?
oderstring
, und stellen Sie benutzerdefinierte Logik zur Behandlung ungültiger Einträge bereit.Bind to a nullable type, such asint?
orstring
and provide custom logic to handle invalid entries. - Verwenden Sie eine Formularüberprüfungskomponente wie InputNumber<TValue> oder InputDate<TValue>.Use a form validation component, such as InputNumber<TValue> or InputDate<TValue>. Formularüberprüfungskomponenten verfügen über die integrierte Unterstützung der Verwaltung ungültiger Eingaben.Form validation components have built-in support to manage invalid inputs. Weitere Informationen finden Sie unter Blazor-Formulare und -Validierung in ASP.NET Core.For more information, see Blazor-Formulare und -Validierung in ASP.NET Core. Formularüberprüfungskomponenten:Form validation components:
- Erlauben Sie dem Benutzer, ungültige Eingaben zu machen und Überprüfungsfehler für das zugehörige EditContext zu erhalten.Permit the user to provide invalid input and receive validation errors on the associated EditContext.
- Zeigen Sie Überprüfungsfehler auf der Benutzeroberfläche an, ohne den Benutzer bei der Eingabe zusätzlicher WebForm-Daten zu beeinträchtigen.Display validation errors in the UI without interfering with the user entering additional webform data.
FormatzeichenfolgenFormat strings
Die Datenbindung funktioniert mit DateTime-Formatzeichenfolgen, die @bind:format
verwenden.Data binding works with DateTime format strings using @bind:format
. Andere Formatausdrücke wie Währungs- oder Zahlenformate sind zu diesem Zeitpunkt nicht verfügbar.Other format expressions, such as currency or number formats, aren't available at this time.
<input @bind="startDate" @bind:format="yyyy-MM-dd" />
@code {
private DateTime startDate = new DateTime(2020, 1, 1);
}
Im vorhergehenden Code ist der Feldtyp des <input>
-Elements (type
) standardmäßig auf text
festgelegt.In the preceding code, the <input>
element's field type (type
) defaults to text
. @bind:format
wird für die Bindung der folgenden .NET-Typen unterstützt:@bind:format
is supported for binding the following .NET types:
- System.DateTime
- System.DateTime?System.DateTime?
- System.DateTimeOffset
- System.DateTimeOffset?System.DateTimeOffset?
Das @bind:format
-Attribut gibt das Datumsformat an, das auf den value
des <input>
-Elements angewendet werden soll.The @bind:format
attribute specifies the date format to apply to the value
of the <input>
element. Das Format wird auch verwendet, um den Wert beim Eintreten eines onchange
-Ereignisses zu analysieren.The format is also used to parse the value when an onchange
event occurs.
Die Angabe eines Formats für den Feldtyp date
wird nicht empfohlen, da Blazor eine integrierte Unterstützung für die Formatierung von Daten bietet.Specifying a format for the date
field type isn't recommended because Blazor has built-in support to format dates. Verwenden Sie trotz der Empfehlung nur dann das Datumsformat yyyy-MM-dd
für die Bindung, um ordnungsgemäß zu funktionieren, wenn ein Format mit dem Feldtyp date
bereitgestellt wird:In spite of the recommendation, only use the yyyy-MM-dd
date format for binding to function correctly if a format is supplied with the date
field type:
<input type="date" @bind="startDate" @bind:format="yyyy-MM-dd">
Binden mit KomponentenparameternBinding with component parameters
Ein häufiges Szenario besteht darin, eine Eigenschaft in einer untergeordneten Komponente an eine Eigenschaft in ihrem übergeordneten Element zu binden.A common scenario is binding a property in a child component to a property in its parent. Dieses Szenario wird als verkettete Bindung bezeichnet, da mehrere Ebenen der Bindung gleichzeitig auftreten.This scenario is called a chained bind because multiple levels of binding occur simultaneously.
Komponentenparameter erlauben das Binden von Eigenschaften und Feldern einer übergeordneten Komponente mit @bind-{PROPERTY OR FIELD}
-Syntax.Component parameters permit binding properties and fields of a parent component with @bind-{PROPERTY OR FIELD}
syntax.
Verkettete Bindungen können nicht mit der @bind
-Syntax in der untergeordneten Komponente implementiert werden.Chained binds can't be implemented with @bind
syntax in the child component. Separat müssen ein Ereignishandler und ein Wert angegeben werden, um die Aktualisierung der Eigenschaft in der übergeordneten Komponente zu unterstützen.An event handler and value must be specified separately to support updating the property in the parent from the child component.
Die übergeordnete Komponente nutzt weiterhin die @bind
-Syntax, um die Datenbindung mit der untergeordneten Komponente einzurichten.The parent component still leverages the @bind
syntax to set up the data-binding with the child component.
Die folgende Child
-Komponente (Shared/Child.razor
) verfügt über einen Year
-Komponentenparameter und YearChanged
-Rückruf:The following Child
component (Shared/Child.razor
) has a Year
component parameter and YearChanged
callback:
<div class="card bg-light mt-3" style="width:18rem ">
<div class="card-body">
<h3 class="card-title">Child Component</h3>
<p class="card-text">Child <code>Year</code>: @Year</p>
</div>
</div>
<button @onclick="UpdateYearFromChild">Update Year from Child</button>
@code {
private Random r = new Random();
[Parameter]
public int Year { get; set; }
[Parameter]
public EventCallback<int> YearChanged { get; set; }
private async Task UpdateYearFromChild()
{
await YearChanged.InvokeAsync(r.Next(1950, 2021));
}
}
Der Rückruf (EventCallback<TValue>) muss den Namen des Komponentenparameters aufweisen, gefolgt vom Suffix „Changed
“ ({PARAMETER NAME}Changed
).The callback (EventCallback<TValue>) must be named as the component parameter name followed by the "Changed
" suffix ({PARAMETER NAME}Changed
). Im vorherigen Beispiel trägt der Rückruf den Namen YearChanged
.In the preceding example, the callback is named YearChanged
. EventCallback.InvokeAsync ruft den Delegaten, der der Bindung zugeordnet ist, mit dem bereitgestellten Argument auf und sendet eine Ereignisbenachrichtigung über die geänderte Eigenschaft.EventCallback.InvokeAsync invokes the delegate associated with the binding with the provided argument and dispatches an event notification for the changed property.
In der folgenden Parent
-Komponente (Parent.razor
) ist das Feld year
an den Year
-Parameter der untergeordneten Komponente gebunden:In the following Parent
component (Parent.razor
), the year
field is bound to the Year
parameter of the child component:
@page "/Parent"
<h1>Parent Component</h1>
<p>Parent <code>year</code>: @year</p>
<button @onclick="UpdateYear">Update Parent <code>year</code></button>
<Child @bind-Year="year" />
@code {
private Random r = new Random();
private int year = 1979;
private void UpdateYear()
{
year = r.Next(1950, 2021);
}
}
Der Parameter Year
ist bindbar, da er ein Begleitereignis YearChanged
aufweist, das dem Typ des Parameters Year
entspricht.The Year
parameter is bindable because it has a companion YearChanged
event that matches the type of the Year
parameter.
Gemäß der Konvention kann eine Eigenschaft an einen entsprechenden Ereignishandler gebunden werden, indem ein @bind-{PROPERTY}:event
-Attribut einbezogen wird, das dem Handler zugewiesen ist.By convention, a property can be bound to a corresponding event handler by including an @bind-{PROPERTY}:event
attribute assigned to the handler. <Child @bind-Year="year" />
ist identisch mit dem folgenden Code:<Child @bind-Year="year" />
is equivalent to writing:
<Child @bind-Year="year" @bind-Year:event="YearChanged" />
In einem komplexeren Beispiel aus der Praxis wird die PasswordField
-Komponente (PasswordField.razor
) für Folgendes verwendet:In a more sophisticated and real-world example, the following PasswordField
component (PasswordField.razor
):
- Legt den Wert eines
<input>
-Elements auf einpassword
-Feld fest.Sets an<input>
element's value to apassword
field. - Macht Änderungen einer
Password
-Eigenschaft einer übergeordneten Komponente mit einemEventCallback
verfügbar, der den aktuellen Wert despassword
-Felds des untergeordneten Elements als Argument übergibt.Exposes changes of aPassword
property to a parent component with anEventCallback
that passes in the current value of the child'spassword
field as its argument. - Verwendet das
onclick
-Ereignis zum Auslösen derToggleShowPassword
-Methode.Uses theonclick
event to trigger theToggleShowPassword
method. Weitere Informationen finden Sie unter ASP.NET Core Blazor-Ereignisbehandlung.For more information, see ASP.NET Core Blazor-Ereignisbehandlung.
<h1>Provide your password</h1>
Password:
<input @oninput="OnPasswordChanged"
required
type="@(showPassword ? "text" : "password")"
value="@password" />
<button class="btn btn-primary" @onclick="ToggleShowPassword">
Show password
</button>
@code {
private bool showPassword;
private string password;
[Parameter]
public string Password { get; set; }
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
private async Task OnPasswordChanged(ChangeEventArgs e)
{
password = e.Value.ToString();
await PasswordChanged.InvokeAsync(password);
}
private void ToggleShowPassword()
{
showPassword = !showPassword;
}
}
Die PasswordField
-Komponente wird in einer anderen Komponente verwendet:The PasswordField
component is used in another component:
@page "/Parent"
<h1>Parent Component</h1>
<PasswordField @bind-Password="password" />
@code {
private string password;
}
Führen Sie Prüfungen durch, oder fangen Sie Fehler in der Methode ab, die den Delegat der Bindung aufruft.Perform checks or trap errors in the method that invokes the binding's delegate. Das folgende Beispiel gibt dem Benutzer ein sofortiges Feedback, wenn ein Leerzeichen im Wert des Kennworts verwendet wird:The following example provides immediate feedback to the user if a space is used in the password's value:
<h1>Child Component</h1>
Password:
<input @oninput="OnPasswordChanged"
required
type="@(showPassword ? "text" : "password")"
value="@password" />
<button class="btn btn-primary" @onclick="ToggleShowPassword">
Show password
</button>
<span class="text-danger">@validationMessage</span>
@code {
private bool showPassword;
private string password;
private string validationMessage;
[Parameter]
public string Password { get; set; }
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
private Task OnPasswordChanged(ChangeEventArgs e)
{
password = e.Value.ToString();
if (password.Contains(' '))
{
validationMessage = "Spaces not allowed!";
return Task.CompletedTask;
}
else
{
validationMessage = string.Empty;
return PasswordChanged.InvokeAsync(password);
}
}
private void ToggleShowPassword()
{
showPassword = !showPassword;
}
}
Weitere Informationen zu EventCallback<TValue> finden Sie unter ASP.NET Core Blazor-Ereignisbehandlung.For more information on EventCallback<TValue>, see ASP.NET Core Blazor-Ereignisbehandlung.
Binden über mehr als zwei KomponentenBind across more than two components
Sie können eine Bindung über eine beliebige Anzahl geschachtelter Komponenten erstellen, Sie müssen aber den unidirektionalen Datenfluss berücksichtigen:You can bind through any number of nested components, but you must respect the one-way flow of data:
- Änderungsbenachrichtigungen durchlaufen die Hierarchie von unten nach oben.Change notifications flow up the hierarchy.
- Neue Parameterwerte durchlaufen die Hierarchie von oben nach unten.New parameter values flow down the hierarchy.
Ein gängiges und empfohlenes Verfahren besteht darin, nur die zugrunde liegenden Daten in der übergeordneten Komponente zu speichern, damit Sie immer genau wissen, welcher Zustand aktualisiert werden muss.A common and recommended approach is to only store the underlying data in the parent component to avoid any confusion about what state must be updated.
Die folgenden Komponenten veranschaulichen die oben beschriebenen Konzepte:The following components demonstrate the preceding concepts:
ParentComponent.razor
:ParentComponent.razor
:
<h1>Parent Component</h1>
<p>Parent Message: <b>@parentMessage</b></p>
<p>
<button @onclick="ChangeValue">Change from Parent</button>
</p>
<ChildComponent @bind-ChildMessage="parentMessage" />
@code {
private string parentMessage = "Initial value set in Parent";
private void ChangeValue()
{
parentMessage = $"Set in Parent {DateTime.Now}";
}
}
ChildComponent.razor
:ChildComponent.razor
:
<div class="border rounded m-1 p-1">
<h2>Child Component</h2>
<p>Child Message: <b>@ChildMessage</b></p>
<p>
<button @onclick="ChangeValue">Change from Child</button>
</p>
<GrandchildComponent @bind-GrandchildMessage="BoundValue" />
</div>
@code {
[Parameter]
public string ChildMessage { get; set; }
[Parameter]
public EventCallback<string> ChildMessageChanged { get; set; }
private string BoundValue
{
get => ChildMessage;
set => ChildMessageChanged.InvokeAsync(value);
}
private async Task ChangeValue()
{
await ChildMessageChanged.InvokeAsync(
$"Set in Child {DateTime.Now}");
}
}
GrandchildComponent.razor
:GrandchildComponent.razor
:
<div class="border rounded m-1 p-1">
<h3>Grandchild Component</h3>
<p>Grandchild Message: <b>@GrandchildMessage</b></p>
<p>
<button @onclick="ChangeValue">Change from Grandchild</button>
</p>
</div>
@code {
[Parameter]
public string GrandchildMessage { get; set; }
[Parameter]
public EventCallback<string> GrandchildMessageChanged { get; set; }
private async Task ChangeValue()
{
await GrandchildMessageChanged.InvokeAsync(
$"Set in Grandchild {DateTime.Now}");
}
}
Einen alternativen Ansatz, der sich für die arbeitsspeicherinterne und komponentenübergreifende Datenfreigabe eignet (Komponenten müssen nicht unbedingt geschachtelt sein), finden Sie im Abschnitt In-Memory-Zustandscontainerdienst unter Blazor-Zustandsverwaltung in ASP.NET Core.For an alternative approach suited to sharing data in-memory across components that aren't necessarily nested, see the In-memory state container service section of Blazor-Zustandsverwaltung in ASP.NET Core.