Initialisation des systèmes...

Baptiste.Dev
Retour aux notes
FrameworksIntermédiaireSérie : Blazor / Razor

Blazor : le data binding

@bind en profondeur : événement de déclenchement, format et culture, @bind:get/set et @bind:after, et comment rendre un composant bindable avec la convention Value / ValueChanged.

Par Baptiste Vidal
3 min de lecture
Mis à jour il y a 2 semaines
blazorrazordotnetbindingformulairescomposants

Blazor : le data binding

@bind est apparu vite dans les composants. Derrière ce petit mot-clé se cache tout un système : événement de déclenchement, format, culture, callbacks, et liaison bidirectionnelle entre composants. On déplie.


# Ce que @bind fait vraiment

@bind="x" est du sucre syntaxique : le compilateur génère à la fois la lecture (value="@x") et l'écriture (@onchange qui réaffecte x). Ces deux écritures sont équivalentes :

<input @bind="nom" />
 
@* Ce que le compilateur génère, en substance : *@
<input value="@nom" @onchange="e => nom = e.Value?.ToString()" />

Une seule direction ne suffit donc pas à comprendre @bind : il lit la valeur pour l'afficher et l'écrit quand l'utilisateur la change.


# @bind:event : quand la valeur remonte

Par défaut, @bind écoute onchange : la valeur ne remonte qu'à la perte de focus. Pour réagir à chaque frappe, cible oninput :

<input @bind="recherche" @bind:event="oninput" />
<p>@recherche.Length caractères saisis</p>

onchange convient à un formulaire qu'on valide à la fin ; oninput à une recherche instantanée ou un compteur en direct.


# @bind:format et la culture

Pour les dates et les nombres, @bind:format contrôle la conversion vers la chaîne affichée :

<input type="date" @bind="dateNaissance" @bind:format="yyyy-MM-dd" />

Piège culture : @bind parse et formate avec la culture courante du thread. En fr-FR, 1,5 est accepté mais 1.5 échoue. Pour un format déterministe (stockage, API), impose la culture avec @bind:culture="Culture" (un champ CultureInfo), typiquement CultureInfo.InvariantCulture.


# @bind:get / @bind:set : le contrôle total

Depuis .NET 7, tu peux dissocier lecture et écriture pour intercaler ta propre logique (validation, normalisation) :

<input @bind:get="nom" @bind:set="MettreAJourNom" />
 
@code {
    private string nom = "";
    private void MettreAJourNom(string valeur) => nom = valeur.Trim();
}

Et @bind:after (.NET 8) déclenche une action après la mise à jour de la valeur, sans casser le binding :

<input @bind="filtre" @bind:after="Rechercher" />
 
@code {
    private string filtre = "";
    private async Task Rechercher() { /* relance la requête filtrée */ }
}

# Rendre un composant bindable (@bind-Value)

Pour qu'un parent puisse écrire @bind-Value sur ton composant, respecte la convention Value + ValueChanged (et, pour la validation, ValueExpression) :

@* ChampTexte.razor *@
<input value="@Value"
       @onchange="e => ValueChanged.InvokeAsync(e.Value?.ToString())" />
 
@code {
    [Parameter] public string? Value { get; set; }
    [Parameter] public EventCallback<string?> ValueChanged { get; set; }
}
@* Utilisation : liaison bidirectionnelle avec le parent *@
<ChampTexte @bind-Value="nom" />

@bind-Value="nom" se déplie en Value="nom" plus un ValueChanged qui réaffecte nom. La paire Xxx / XxxChanged est la mécanique du binding entre composants.


# À retenir

  • @bind = sucre pour lecture (value) + écriture (@onchange).
  • @bind:event="oninput" remonte la valeur à chaque frappe plutôt qu'à la perte de focus.
  • @bind:format et la culture régissent dates et nombres ; méfie-toi du fr-FR sur les décimaux.
  • @bind:get/@bind:set (.NET 7) et @bind:after (.NET 8) donnent le contrôle total.
  • Un composant devient bindable via la convention Value + ValueChanged (@bind-Value).

Prochaine étape : fournir des services à tes composants avec l'injection de dépendances.