Partage via


Composants Razor ASP.NET Core

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la Stratégie de prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Cet article explique comment créer et utiliser des composants Razor dans des applications Blazor et fournit des conseils sur la syntaxe Razor, le nommage de composants, les espaces de noms et les paramètres de composant.

Composants Razor

Les applications Blazor sont créées en utilisant Razor composants de , communément appelés composants deBlazor ou uniquement composants. Un composant est une partie autonome de l’interface utilisateur (IU), avec une logique de traitement pour prendre en charge le comportement dynamique. Les composants peuvent être imbriqués, réutilisés, partagés entre plusieurs projets et utilisés dans des applications MVC et Razor Pages.

Les composants s’affichent dans une représentation en mémoire du modèle DOM (Document Object Model) du navigateur, appelée arborescence de rendu, qui permet de mettre à jour l’IU de manière flexible et efficace.

Bien que les « composants Razor » partagent certains éléments de noms avec d’autres technologies de rendu de contenu ASP.NET Core, les composants Razor doivent être différenciés des différentes fonctionnalités suivantes dans ASP.NET Core :

Important

Lors de l’utilisation d’une Blazor Web App, la plupart des composants de l’exemple de documentation Blazornécessitent une interactivité pour fonctionner et démontrer les concepts couverts par les articles. Lorsque vous testez un composant d’exemple fourni par un article, assurez-vous que l’application adopte une interactivité globale ou que le composant adopte un mode de rendu interactif. Plus d’informations sur ce sujet sont fournies par dans Modes de rendu ASP.NET Core Blazor, qui est l’article suivant dans la table des matières après cet article.

Classes de composant

Les composants sont implémentés en utilisant une combinaison de balises C# et HTML dans des fichiers de composants Razor avec l’extension de fichier .razor.

ComponentBase est la classe de base pour les composants décrits par les fichiers de composants Razor. ComponentBase implémente l’abstraction la plus faible des composants, l’interface IComponent. ComponentBase définit des propriétés et des méthodes de composant pour les fonctionnalités de base, par exemple pour traiter un ensemble d’événements de cycle de vie de composant intégrés.

ComponentBase dans la dotnet/aspnetcore source de référence : la source de référence contient des remarques supplémentaires sur les événements de cycle de vie intégrés. Toutefois, gardez à l’esprit que les implémentations internes des fonctionnalités de composant sont susceptibles d’être modifiées à tout moment sans préavis.

Remarque

Les liens de documentation vers la source de référence .NET chargent généralement la branche par défaut du référentiel, qui représente le développement actuel pour la prochaine version de .NET. Pour sélectionner une balise pour une version spécifique, utilisez la liste déroulante Échanger les branches ou les balises. Pour plus d’informations, consultez Comment sélectionner une balise de version du code source ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Les développeurs créent Razor généralement des composants à partir de fichiers de composants Razor (.razor) ou basent leurs composants sur ComponentBase, mais les composants peuvent également être générés en implémentant IComponent. Les composants créés par le développeur qui implémentent IComponent peuvent prendre un contrôle de bas niveau sur le rendu au prix de devoir déclencher manuellement le rendu avec des événements et des méthodes de cycle de vie que le développeur doit créer et gérer.

Des conventions supplémentaires adoptées par des exemples de code de documentation Blazor et des exemples d’applications se trouvent dans Notions fondamentales Blazor ASP.NET Core.

Syntaxe de Razor

Les composants suivent la syntaxe Razor. Deux fonctionnalités Razor sont largement utilisées par les composants : les directives et les attributs de directive. Il s’agit de mots clés réservés, préfixés par @, qui apparaissent dans le balisage Razor :

  • Directives : modifient le mode de compilation ou de fonctionnement du balisage d’un composant. Par exemple, la directive @page spécifie un composant routable avec un modèle de routage accessible directement sur demande d’un utilisateur dans le navigateur à une URL spécifique.

    Par convention, les directives d’un composant en haut d’une définition de composant (fichier .razor) sont placées dans un ordre cohérent. Pour les directives répétées, les directives sont placées par ordre alphabétique par espace de noms ou par type, à l’exception des directives @using, qui ont un ordre spécial de second niveau.

    L’ordre suivant est adopté par des exemples d’applications et de documentation Blazor. Les composants fournis par un modèle de projet Blazor peuvent différer de l’ordre suivant et utiliser un autre format. Par exemple, les composants Identity du framework Blazorincluent des lignes vides entre des blocs de directives @using et des blocs de directives @inject. Vous êtes libre d’utiliser un format et un schéma de classement personnalisé dans vos propres applications.

    Documentation et exemple d’ordre de directive d’application Razor :

    • @page
    • @rendermode (.NET 8 ou version ultérieure)
    • @using
      • Espaces de noms de System (ordre alphabétique)
      • Espaces de noms de Microsoft (ordre alphabétique)
      • Espaces de noms d’API tiers (ordre alphabétique)
      • Espaces de noms d’application (ordre alphabétique)
    • Autres directives (ordre alphabétique)

    Aucune ligne vide n’apparaît parmi les directives. Une ligne vide apparaît entre les directives et la première ligne du balisage Razor.

    Exemple :

    @page "/doctor-who-episodes/{season:int}"
    @rendermode InteractiveWebAssembly
    @using System.Globalization
    @using System.Text.Json
    @using Microsoft.AspNetCore.Localization
    @using Mandrill
    @using BlazorSample.Components.Layout
    @attribute [Authorize]
    @implements IAsyncDisposable
    @inject IJSRuntime JS
    @inject ILogger<DoctorWhoEpisodes> Logger
    
    <PageTitle>Doctor Who Episode List</PageTitle>
    
    ...
    
  • Attributs de directive : modifient le mode de compilation ou de fonctionnement d’un élément de composant.

    Exemple :

    <input @bind="episodeId" />
    

    Vous pouvez préfixer les valeurs d’attribut de directive avec le symbole @ pour les expressions Razor non explicites (@bind="@episodeId"), mais nous vous le déconseillons. Par conséquent, les exemples donnés dans les documents n’adoptent pas cette approche.

Les directives et attributs de directive utilisés dans des composants sont expliqués plus loin dans cet article et dans d’autres articles de la documentation Blazor. Pour obtenir une description générale de la syntaxe Razor, consultez les informations de référence sur la syntaxe Razor pour ASP.NET Core.

Nom du composant, nom de classe et espace de noms

Le nom d’un composant doit commencer par une majuscule :

Pris en charge : ProductDetail.razor

Non pris en charge : productDetail.razor

Parmi les conventions de nommage Blazor couramment utilisées dans la documentation Blazor, citons les suivantes :

  • Les chemins d’accès aux fichiers et les noms de fichiers utilisent la casse Pascal† et apparaissent avant d’afficher des exemples de code. Si un chemin d’accès est présent, il indique l’emplacement du dossier classique. Par exemple, Components/Pages/ProductDetail.razor indique que le composant ProductDetail a pour nom de fichier ProductDetail.razor et réside dans le dossier Pages du dossier Components de l’application.
  • Les chemins aux fichiers de composants routables correspondent à leurs URL dans le kebab case ‡ avec des tirets apparaissant entre les mots dans le modèle de routage d’un composant. Par exemple, un composant ProductDetail avec le modèle de routage /product-detail (@page "/product-detail") est demandé dans un navigateur à l’URL relative /product-detail.

†La casse Pascal (casse mixte avec majuscules) est une convention de nommage sans espaces ni ponctuation où la première lettre de chaque mot est en majuscule, y compris le premier mot.
La casse kebab est une convention d’affectation de noms sans espaces et ponctuation qui utilise des lettres minuscules et des tirets entre les mots.

Les composants sont des classes C# ordinaires que vous pouvez placer n’importe où dans un projet. Les composants qui produisent des pages web résident généralement dans le dossier Components/Pages. Les composants autres que des pages sont fréquemment placés dans le dossier Components ou dans un dossier personnalisé ajouté au projet.

En général, l’espace de noms d’un composant est dérivé de l’espace de noms racine de l’application et de l’emplacement (dossier) du composant dans l’application. Si l’espace de noms racine de l’application est BlazorSample et que le composant Counter réside dans le dossier Components/Pages :

  • L’espace de noms du composant Counter est BlazorSample.Components.Pages.
  • Le nom de type complet du composant est BlazorSample.Components.Pages.Counter.

Pour les dossiers personnalisés contenant des composants, ajoutez une directive @using au composant parent ou au fichier _Imports.razor de l’application. L’exemple suivant rend les composants du dossier AdminComponents disponibles :

@using BlazorSample.AdminComponents

Remarque

Les directives @using dans le fichier _Imports.razor ne s’appliquent qu’aux fichiers Razor (.razor), pas aux fichiers C# (.cs).

Les instructions alias using sont prises en charge. Dans l’exemple suivant, la classe publique WeatherForecast du composantGridRendering est rendue disponible comme WeatherForecast dans un composant situé ailleurs dans l’application :

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

Vous pouvez également référencer des composants avec leurs noms complets, ce qui ne nécessite pas de directive @using. L’exemple suivant référence directement le composant ProductDetail dans le dossier AdminComponents/Pages de l’application :

<BlazorSample.AdminComponents.Pages.ProductDetail />

L’espace de noms d’un composant créé avec Razor est basé sur les éléments suivants (par ordre de priorité) :

  • Directive @namespace dans le balisage du fichier Razor (par exemple, @namespace BlazorSample.CustomNamespace).
  • RootNamespace du projet dans le fichier de projet (par exemple, <RootNamespace>BlazorSample</RootNamespace>).
  • Les Espace de noms du projet et chemin d’accès de la racine du projet au composant. Par exemple, le framework résout {PROJECT NAMESPACE}/Components/Pages/Home.razor avec l’espace de noms de projet BlazorSample en espace de noms BlazorSample.Components.Pages pour le composant Home. {PROJECT NAMESPACE} est l’espace de noms du projet. Les composants suivent les règles de liaison de nom C#. Pour le composant Home de cet exemple, les composants dans l’étendue sont tous les composants :
    • Dans le même dossier, Components/Pages.
    • Composants à la racine du projet qui ne spécifient pas explicitement un autre espace de noms.

Les éléments suivants ne sont pas pris en charge :

  • Qualification global::.
  • Noms partiellement qualifiés. Par exemple, vous ne pouvez pas ajouter @using BlazorSample.Components à un composant, puis référencer le composant NavMenu dans le dossier Components/Layout de l’application (Components/Layout/NavMenu.razor) avec <Layout.NavMenu></Layout.NavMenu>.

Le nom d’un composant doit commencer par une majuscule :

Pris en charge : ProductDetail.razor

Non pris en charge : productDetail.razor

Parmi les conventions de nommage Blazor couramment utilisées dans la documentation Blazor, citons les suivantes :

  • Les chemins d’accès aux fichiers et les noms de fichiers utilisent la casse Pascal† et apparaissent avant d’afficher des exemples de code. Si un chemin d’accès est présent, il indique l’emplacement du dossier classique. Par exemple, Pages/ProductDetail.razor indique que le composant ProductDetail a pour nom de fichier ProductDetail.razor et réside dans le dossier Pages de l’application.
  • Les chemins aux fichiers de composants routables correspondent à leurs URL dans le kebab case ‡ avec des tirets apparaissant entre les mots dans le modèle de routage d’un composant. Par exemple, un composant ProductDetail avec le modèle de routage /product-detail (@page "/product-detail") est demandé dans un navigateur à l’URL relative /product-detail.

†La casse Pascal (casse mixte avec majuscules) est une convention de nommage sans espaces ni ponctuation où la première lettre de chaque mot est en majuscule, y compris le premier mot.
La casse kebab est une convention d’affectation de noms sans espaces et ponctuation qui utilise des lettres minuscules et des tirets entre les mots.

Les composants sont des classes C# ordinaires que vous pouvez placer n’importe où dans un projet. Les composants qui produisent des pages web résident généralement dans le dossier Pages. Les composants autres que des pages sont fréquemment placés dans le dossier Shared ou dans un dossier personnalisé ajouté au projet.

En général, l’espace de noms d’un composant est dérivé de l’espace de noms racine de l’application et de l’emplacement (dossier) du composant dans l’application. Si l’espace de noms racine de l’application est BlazorSample et que le composant Counter réside dans le dossier Pages :

  • L’espace de noms du composant Counter est BlazorSample.Pages.
  • Le nom de type complet du composant est BlazorSample.Pages.Counter.

Pour les dossiers personnalisés contenant des composants, ajoutez une directive @using au composant parent ou au fichier _Imports.razor de l’application. L’exemple suivant rend les composants du dossier AdminComponents disponibles :

@using BlazorSample.AdminComponents

Remarque

Les directives @using dans le fichier _Imports.razor ne s’appliquent qu’aux fichiers Razor (.razor), pas aux fichiers C# (.cs).

Les instructions alias using sont prises en charge. Dans l’exemple suivant, la classe publique WeatherForecast du composantGridRendering est rendue disponible comme WeatherForecast dans un composant situé ailleurs dans l’application :

@using WeatherForecast = Pages.GridRendering.WeatherForecast

Vous pouvez également référencer des composants avec leurs noms complets, ce qui ne nécessite pas de directive @using. L’exemple suivant référence directement le composant ProductDetail dans le dossier Components de l’application :

<BlazorSample.Components.ProductDetail />

L’espace de noms d’un composant créé avec Razor est basé sur les éléments suivants (par ordre de priorité) :

  • Directive @namespace dans le balisage du fichier Razor (par exemple, @namespace BlazorSample.CustomNamespace).
  • RootNamespace du projet dans le fichier de projet (par exemple, <RootNamespace>BlazorSample</RootNamespace>).
  • Les Espace de noms du projet et chemin d’accès de la racine du projet au composant. Par exemple, le framework résout {PROJECT NAMESPACE}/Pages/Index.razor avec l’espace de noms de projet BlazorSample en espace de noms BlazorSample.Pages pour le composant Index. {PROJECT NAMESPACE} est l’espace de noms du projet. Les composants suivent les règles de liaison de nom C#. Pour le composant Index de cet exemple, les composants dans l’étendue sont tous les composants :
    • Dans le même dossier, Pages.
    • Composants à la racine du projet qui ne spécifient pas explicitement un autre espace de noms.

Les éléments suivants ne sont pas pris en charge :

  • Qualification global::.
  • Noms partiellement qualifiés. Par exemple, vous ne pouvez pas ajouter @using BlazorSample à un composant, puis référencer le composant NavMenu dans le dossier Shared de l’application (Shared/NavMenu.razor) avec <Shared.NavMenu></Shared.NavMenu>.

Prise en charge de classes partielles

Les composants sont générés en tant que classes partielles C# et sont créés à l’aide de l’une des approches suivantes :

  • Un seul fichier contient du code C# défini dans un ou plusieurs blocs @code, un balisage HTML et un balisage Razor. Les modèles de projet Blazor définissent leurs composants à l’aide de cette approche monofichier.
  • Les balisages HTML et Razor sont placés dans un fichier Razor (.razor). Le code C# est placé dans un fichier code-behind défini en tant que classe partielle (.cs).

Remarque

Une feuille de style de composant qui définit des styles spécifiques aux composants est un fichier distinct (.css). L’isolation CSS Blazor est décrite plus loin dans Isolation CSS dans Blazor ASP.NET Core.

L’exemple suivant montre le composant Counter par défaut avec un bloc @code dans une application générée à partir d’un modèle de projet Blazor. Le balisage et le code C# sont dans le même fichier. Il s’agit de l’approche la plus couramment adoptée pour créer des composants.

Counter.razor:

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount() => currentCount++;
}
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount() => currentCount++;
}
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Le composant Counter suivant sépare le balisage de la présentation HTML et le Razor du code C# en utilisant un fichier code-behind avec une classe partielle. Le fractionnement du balisage du code C# est privilégié par certaines organisations et développeurs pour organiser leur code de composant en fonction de leur mode de travail. Par exemple, l’expert en interface utilisateur de l’organisation peut travailler sur la couche de présentation indépendamment d’un autre développeur sui travaille sur la logique C# du composant. L’approche est également utile lors de l’utilisation de générateurs de code ou de sources générés automatiquement. Pour plus d’informations, consultez Classes et méthodes partielles (Guide de programmation C#).

CounterPartialClass.razor:

@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

CounterPartialClass.razor.cs:

namespace BlazorSample.Components.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

    private void IncrementCount() => currentCount++;
}
namespace BlazorSample.Components.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

    private void IncrementCount() => currentCount++;
}
namespace BlazorSample.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
namespace BlazorSample.Pages
{
    public partial class CounterPartialClass
    {
        private int currentCount = 0;

        private void IncrementCount()
        {
            currentCount++;
        }
    }
}

Les directives @using dans le fichier _Imports.razor ne s’appliquent qu’aux fichiers Razor (.razor), pas aux fichiers C# (.cs). Ajoutez des espaces de noms à un fichier de classe partielle en fonction des besoins.

Espaces de noms standard utilisés par les composants :

using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Sections
using Microsoft.AspNetCore.Components.Web;
using static Microsoft.AspNetCore.Components.Web.RenderMode;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;

Les espaces de noms standard incluent également l’espace de noms de l’application et l’espace de noms correspondant au dossier Components de l’application :

using BlazorSample;
using BlazorSample.Components;

Des dossiers supplémentaires peuvent également être inclus, tels que le dossier Layout :

using BlazorSample.Components.Layout;
using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;

Les espaces de noms standard incluent également l’espace de noms de l’application et l’espace de noms correspondant au dossier Shared de l’application :

using BlazorSample;
using BlazorSample.Shared;
using System.Net.Http;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;

Les espaces de noms standard incluent également l’espace de noms de l’application et l’espace de noms correspondant au dossier Shared de l’application :

using BlazorSample;
using BlazorSample.Shared;

Spécifier une classe de base

La directive @inherits est utilisée pour spécifier la classe de base d’un composant. Contrairement à l’utilisation de classes partielles, qui fractionne uniquement le balisage de la logique C#, l’utilisation d’une classe de base vous permet d’hériter du code C# pour une utilisation dans un groupe de composants qui partagent les propriétés et méthodes de la classe de base. L’utilisation de classes de base réduit la redondance du code dans les applications et est utile lorsque vous fournissez du code de base des bibliothèques de classes à plusieurs applications. Pour plus d’informations, consultez Héritage en C# et .NET.

Dans l’exemple suivant, la classe de base BlazorRocksBase1 dérive de ComponentBase.

BlazorRocks1.razor:

@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>

BlazorRocksBase1.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}

Routage

Pour router dans Blazor, un modèle de routage est fourni à chaque composant accessible dans l’application avec une directive @page. Quand un fichier Razor avec une directive @page est compilé, la classe générée reçoit un RouteAttribute spécifiant le modèle de routage. Au moment de l’exécution, le routeur recherche les classes de composant avec un RouteAttribute et génère le rendu du composant dont le modèle de routage correspond à l’URL demandée.

Le composant suivant HelloWorld utilise un modèle d’itinéraire de /hello-world, et la page web rendue pour le composant est atteinte à l’URL /hello-worldrelative.

HelloWorld.razor:

@page "/hello-world"

<PageTitle>Hello World!</PageTitle>

<h1>Hello World!</h1>
@page "/hello-world"

<PageTitle>Hello World!</PageTitle>

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>

Le composant précédent se charge dans le navigateur à l’adresse /hello-world, que vous ajoutiez ou non le composant à la navigation de l’interface utilisateur de l’application. Si vous le souhaitez, vous pouvez ajouter un composant au composant NavMenu pour faire apparaître un lien vers le composant dans la navigation basée sur l’interface utilisateur de l’application.

Pour le composant HelloWorld précédent, vous pouvez ajouter un composant NavLink au composant NavMenu. Pour obtenir plus d’informations, notamment les descriptions des composants NavLink et NavMenu, consultez Routage et navigation dans Blazor ASP.NET Core.

balisage

L’interface utilisateur d’un composant est définie à l’aide de la syntaxe Razor, qui comprend le balisage Razor et du code C# et HTML. Quand une application est compilée, le balisage HTML et la logique de rendu C# sont convertis en classe de composant. Le nom de la classe générée correspond au nom du fichier.

Les membres de la classe de composant sont définis dans un ou plusieurs blocs @code. Dans les blocs @code, l’état du composant est spécifié et traité avec C# :

  • Initialiseurs de propriété et de champ.
  • Valeurs de paramètre à partir d’arguments passés par les composants parents et les paramètres de routage.
  • Méthodes de gestion des événements utilisateur, des événements de cycle de vie et de la logique des composants personnalisés.

Les membres d’un composant sont utilisés dans la logique de rendu au moyen d’expressions C# qui commencent par le symbole @. Par exemple, un champ C# est rendu en préfixant @ au nom du champ. Le composant Markup suivant évalue ce qui suit et en génère le rendu :

  • headingFontStyle pour la valeur de propriété CSS font-style de l’élément de titre.
  • headingText pour le contenu de l’élément de titre.

Markup.razor:

@page "/markup"

<PageTitle>Markup</PageTitle>

<h1>Markup Example</h1>

<h2 style="font-style:@headingFontStyle">@headingText</h2>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<PageTitle>Markup</PageTitle>

<h1>Markup Example</h1>

<h2 style="font-style:@headingFontStyle">@headingText</h2>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}

Remarque

Les exemples fournis dans la documentation Blazor spécifient le modificateur d’accès private pour les membres privés. Les membres privés sont délimités à la classe d’un composant. Cependant, C# opte pour le modificateur d’accès private quand aucun modificateur d’accès n’est présent. Vous n’êtes donc pas obligé de marquer explicitement les membres avec « private ». Pour plus d’informations sur les modificateurs d’accès, consultez Modificateurs d’accès (Guide de programmation C#).

Le framework Blazor traite un composant en interne comme une arborescence de rendu, qui est la combinaison du DOM et du modèle de l’objet CSSOM (Cascading Style Sheet Object Model). Après le rendu initial du composant, son arborescence de rendu est regénérée en réponse aux événements. Blazor compare la nouvelle arborescence de rendu à la précédente et applique toute modification apportée au modèle DOM du navigateur pour affichage. Pour plus d’informations, consultez le rendu de composants Razor ASP.NET Core.

Dans la syntaxe Razor, les structures de contrôle, directives et attributs de directive C# sont en minuscules (exemples : @if, @code, @bind). Les noms de propriété sont en majuscules (exemple : @Body pour LayoutComponentBase.Body).

Les méthodes asynchrones (async) ne prennent pas en charge void en retour

Le framework Blazor ne suit pas les méthodes asynchrones retournant void (async). Par conséquent, les exceptions ne sont pas interceptées si void est retourné. Retournez toujours une Task à partir de méthodes asynchrones.

Composants imbriqués

Les composants peuvent inclure d’autres composants en les déclarant avec la syntaxe HTML. Le balisage pour l’utilisation d’un composant ressemble à une balise HTML où le nom de la balise est le type du composant.

Considérez le composant Heading suivant, qui peut être utilisé par d’autres composants pour afficher un titre.

Heading.razor:

<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}

Le balisage suivant dans le composant HeadingExample génère le rendu du composant Heading précédent à l’emplacement où la balise <Heading /> apparaît.

HeadingExample.razor:

@page "/heading-example"

<PageTitle>Heading</PageTitle>

<h1>Heading Example</h1>

<Heading />
@page "/heading-example"

<PageTitle>Heading</PageTitle>

<h1>Heading Example</h1>

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />

Si un composant contient un élément HTML avec une première lettre majuscule qui ne correspond pas à un nom de composant dans le même espace de noms, un avertissement est émis indiquant que l’élément a un nom inattendu. L’ajout d’une directive @using pour l’espace de noms du composant rend le composant disponible, ce qui résout l’avertissement. Pour plus d’informations, consultez la section Nom du composant, nom de la classe et espace de noms.

L’exemple de composant Heading présenté dans cette section n’ayant pas de directive @page, un utilisateur ne peut pas accéder directement au composant Heading par le biais d’une demande directe dans le navigateur. Toutefois, tout composant avec une directive @page peut être imbriqué dans un autre composant. Si l’ajout de @page "/heading" en haut du fichier Razor du composant Heading le rend directement accessible, le composant est alors rendu pour les demandes de navigateur aux emplacements /heading et /heading-example.

Paramètres de composant

Les paramètres de composant passent les données aux composants et sont définis à l’aide de propriétés C# publiques sur la classe de composant avec l’attribut [Parameter]. Dans l’exemple suivant, un type de référence intégré (System.String) et un type de référence défini par l’utilisateur (PanelBody) sont passés en tant que paramètres de composant.

PanelBody.cs:

namespace BlazorSample;

public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
namespace BlazorSample;

public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string Text { get; set; }
    public string Style { get; set; }
}
public class PanelBody
{
    public string Text { get; set; }
    public string Style { get; set; }
}

ParameterChild.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Card content set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Card content set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new PanelBody()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}

Warning

La spécification de valeurs initiales pour les paramètres de composant est prise en charge, mais ne créez pas de composant qui écrit dans ses propres paramètres après le rendu initial du composant. Pour plus d’informations, consultez Éviter le remplacement de paramètres dans ASP.NET Core Blazor.

Les paramètres de composant Title et Body du composant ParameterChild sont définis par des arguments dans la balise HTML qui génère le rendu de l’instance du composant. Le composant ParameterParent suivant génère le rendu de deux composants ParameterChild :

  • Le premier composant ParameterChild est rendu sans fournir d’arguments de paramètre.
  • Le deuxième composant ParameterChild reçoit des valeurs pour Title et Body du composant ParameterParent, qui utilise une expression C# explicite pour définir les valeurs des propriétés de PanelBody.

Parameter1.razor:

@page "/parameter-1"

<PageTitle>Parameter 1</PageTitle>

<h1>Parameter Example 1</h1>

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent" 
    Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

Parameter1.razor:

@page "/parameter-1"

<PageTitle>Parameter 1</PageTitle>

<h1>Parameter Example 1</h1>

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent" 
    Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

Le balisage HTML rendu suivant du composant ParameterParent montre les valeurs par défaut du composant ParameterChild quand le composant ParameterParent ne fournit pas de valeurs de paramètre de composant. Quand le composant ParameterParent fournit des valeurs de paramètre de composant, celles-ci remplacent les valeurs par défaut du composant ParameterChild.

Remarque

Pour plus de clarté, les classes de style CSS rendues ne sont pas affichées dans le balisage HTML rendu suivant.

<h1>Child component (without attribute values)</h1>

<div>
    <div>Set By Child</div>
    <div>Set by child.</div>
</div>

<h1>Child component (with attribute values)</h1>

<div>
    <div>Set by Parent</div>
    <div>Set by parent.</div>
</div>

Affectez un champ C#, une propriété ou le résultat d’une méthode à un paramètre de composant en tant que valeur d’attribut HTML. La valeur de l’attribut peut généralement être n’importe quelle expression C# qui correspond au type du paramètre. La valeur de l’attribut peut éventuellement mener avec un Razor symbole réservé@, mais elle n’est pas obligatoire.

Si le paramètre de composant est de type chaîne, la valeur de l’attribut est traitée comme un littéral de chaîne C#. Si vous souhaitez spécifier une expression C# à la place, utilisez le préfixe @.

Le composant ParameterParent2 suivant affiche quatre instances du composant ParameterChild précédent et définit leurs valeurs de paramètre Title avec :

  • La valeur du champ title.
  • Le résultat de la méthode C# GetTitle.
  • La date locale actuelle au format long avec ToLongDateString, qui utilise une expression C# implicite.
  • La propriété Title de l’objet panelData.

Les guillemets autour des valeurs d’attribut de paramètre sont facultatifs dans la plupart des cas, conformément à la spécification HTML5. Par exemple, Value=this est pris en charge à la place de Value="this". Toutefois, nous vous recommandons d’utiliser des guillemets, car ils sont plus faciles à retenir et sont largement adoptés par les technologies web.

Tout au long de la documentation, les exemples de code se caractérisent comme suit :

  • Ils utilisent toujours des guillemets. Exemple : Value="this".
  • N’utilisez pas le préfixe @ avec des types non littéraux, sauf si nécessaire. Exemple : Count="ct", où ct est une variable de type nombre. Count="@ct" est une approche stylistique valide, mais la documentation et les exemples n’adoptent pas la convention.
  • Toujours éviter @ pour les littéraux, en dehors des expressions Razor. Exemple : IsFixed="true". Cela comprend les mots clés (par exemple,this) etnull, mais vous pouvez choisir de les utiliser si vous le souhaitez. Par exemple, IsFixed="@true" est rare mais pris en charge.

Parameter2.razor:

@page "/parameter-2"

<PageTitle>Parameter 2</PageTitle>

<h1>Parameter Example 2</h1>

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle() => "From Parent method";

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

Parameter2.razor:

@page "/parameter-2"

<PageTitle>Parameter 2</PageTitle>

<h1>Parameter Example 2</h1>

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle() => "From Parent method";

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new PanelData();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

Remarque

Lorsque vous affectez un membre C# à un paramètre de composant, ne préfixez pas l’attribut HTML du paramètre avec @.

Correct (Title est un paramètre de chaîne, Count est un paramètre de type nombre) :

<ParameterChild Title="@title" Count="ct" />
<ParameterChild Title="@title" Count="@ct" />

Incorrect :

<ParameterChild @Title="@title" @Count="ct" />
<ParameterChild @Title="@title" @Count="@ct" />

Contrairement aux pages Razor (.cshtml), Blazor ne peut pas effectuer de travail asynchrone dans une expression Razor lors du rendu d’un composant. En effet, Blazor est conçu pour le rendu d’interfaces utilisateur interactives. Dans une interface utilisateur interactive, l’écran doit toujours afficher quelque chose. Il n’est donc pas judicieux de bloquer le flux de rendu. Au lieu de cela, le travail asynchrone est effectué pendant l’un des événements de cycle de vie asynchrones. Après chaque événement de cycle de vie asynchrone, le composant peut être à nouveau rendu. La syntaxe Razor suivante n’est pas prise en charge :

<ParameterChild Title="await ..." />
<ParameterChild Title="@await ..." />

Le code de l’exemple précédent génère une erreur de compilateur quand l’application est générée :

L’opérateur « await » ne peut être utilisé que dans une méthode asynchrone. Envisagez de marquer cette méthode avec le modificateur « async » et de changer son type de retour en « Task ».

Pour obtenir une valeur pour le paramètre Title dans l’exemple précédent de manière asynchrone, le composant peut utiliser l’événement de cycle de vie OnInitializedAsync, comme le montre l’exemple suivant :

<ParameterChild Title="@title" />

@code {
    private string? title;
    
    protected override async Task OnInitializedAsync()
    {
        title = await ...;
    }
}

Pour plus d’informations, consultez le cycle de vie des composants Razor ASP.NET Core.

L’utilisation d’une expression Razor explicite pour concaténer du texte avec un résultat d’expression pour affectation à un paramètre n’est pas prise en charge. L’exemple suivant cherche à concaténer le texte « Set by  » avec la valeur de propriété d’un objet. Bien que cette syntaxe soit prise en charge dans une page Razor (.cshtml), elle n’est pas valide pour une affectation au paramètre Title de l’enfant dans un composant. La syntaxe Razor suivante n’est pas prise en charge :

<ParameterChild Title="Set by @(panelData.Title)" />

Le code de l’exemple précédent génère une erreur de compilateur quand l’application est générée :

Les attributs de composant ne prennent pas en charge le contenu complexe (mélange C# et balisage).

Pour prendre en charge l’affectation d’une valeur composée, utilisez une méthode, un champ ou une propriété. L’exemple suivant concatène « Set by  » et la valeur de propriété d’un objet dans la méthode C# GetTitle :

Parameter3.razor:

@page "/parameter-3"

<PageTitle>Parameter 3</PageTitle>

<h1>Parameter Example 3</h1>

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

Parameter3.razor:

@page "/parameter-3"

<PageTitle>Parameter 3</PageTitle>

<h1>Parameter Example 3</h1>

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new PanelData();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

Pour en savoir plus, consultez les informations de référence sur la syntaxe Razor pour ASP.NET Core.

Warning

La spécification de valeurs initiales pour les paramètres de composant est prise en charge, mais ne créez pas de composant qui écrit dans ses propres paramètres après le rendu initial du composant. Pour plus d’informations, consultez Éviter le remplacement de paramètres dans ASP.NET Core Blazor.

Les paramètres de composant doivent être déclarés en tant que propriétés automatiques, ce qui signifie qu’ils ne doivent pas contenir de logique personnalisée dans leurs accesseurs get ou set. Par exemple, la propriété StartData suivante est une propriété automatique :

[Parameter]
public DateTime StartData { get; set; }

Ne placez pas de logique personnalisée dans l’accesseur get ou set, car les paramètres de composant servent uniquement de canaux à l’aide desquels un composant parent peut transmettre des informations à un composant enfant. Si un accesseur set d’une propriété de composant enfant contient une logique entraînant un nouveau rendu du composant parent, il en résulte une boucle de rendu infinie.

Pour transformer une valeur de paramètre reçue :

  • Laissez la propriété de paramètre comme propriété automatique pour représenter les données brutes fournies.
  • Créez une autre propriété ou méthode pour fournir les données transformées en fonction de la propriété de paramètre.

Remplacez OnParametersSetAsync pour transformer un paramètre reçu chaque fois que de nouvelles données sont reçues.

L’écriture d’une valeur initiale dans un paramètre de composant est prise en charge, car les affectations de valeurs initiales n’interfèrent pas avec le rendu de composant automatique de Blazor. L’affectation suivante du DateTime local actuel avec DateTime.Now à StartData est une syntaxe valide dans un composant :

[Parameter]
public DateTime StartData { get; set; } = DateTime.Now;

Après l’affectation initiale de DateTime.Now, n’attribuez pas de valeur à StartData dans le code du développeur. Pour plus d’informations, consultez Éviter le remplacement de paramètres dans ASP.NET Core Blazor.

Appliquez l’attribut [EditorRequired] pour spécifier un paramètre de composant obligatoire. Si une valeur de paramètre n’est pas fournie, les éditeurs ou les outils de génération peuvent présenter des avertissements à l’utilisateur. Cet attribut n’est valide que sur les propriétés également marquées avec l’attribut [Parameter]. EditorRequiredAttribute est appliqué au moment de la conception et quand application est générée. L’attribut n’est pas appliqué au moment de l’exécution et ne garantit pas une valeur de paramètre différente de null.

[Parameter]
[EditorRequired]
public string? Title { get; set; }

Les listes d’attributs monolignes sont également prises en charge :

[Parameter, EditorRequired]
public string? Title { get; set; }

N’utilisez pas le modificateurrequired ou l’accesseurinit propriétés des paramètres du composant. Les composants sont généralement instanciés et attribués aux valeurs de paramètre à l’aide de la réflexion, ce qui contourne les garanties qui init et required sont conçus pour effectuer. À la place, appliquez l’attribut[EditorRequired] pour spécifier un paramètre de composant obligatoire.

N’utilisez pas l’accesseurinit sur les propriétés des paramètres de composant, car la définition des valeurs de paramètre de composant avec ParameterView.SetParameterProperties utilise la réflexion, qui contourne la restriction setter init uniquement. Appliquez l’attribut [EditorRequired] pour spécifier un paramètre de composant obligatoire.

N’utilisez pas l’accesseurinit sur les propriétés des paramètres de composant, car la définition des valeurs de paramètre de composant avec ParameterView.SetParameterProperties utilise la réflexion, qui contourne la restriction setter init uniquement.

Les Tuples (documentation de l’API) sont pris en charge pour les paramètres de composant et les types RenderFragment. L’exemple de paramètre de composant suivant passe trois valeurs dans un Tuple :

RenderTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.Item1</li>
            <li>String: @Data?.Item2</li>
            <li>Boolean: @Data?.Item3</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int, string, bool)? Data { get; set; }
}

RenderTupleParent.razor:

@page "/render-tuple-parent"

<PageTitle>Render Tuple Parent</PageTitle>

<h1>Render Tuple Parent Example</h1>

<RenderTupleChild Data="data" />

@code {
    private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}

Les tuples nommés sont pris en charge, comme indiqué dans l’exemple suivant :

NamedTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.TheInteger</li>
            <li>String: @Data?.TheString</li>
            <li>Boolean: @Data?.TheBoolean</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}

NamedTuples.razor:

@page "/named-tuples"

<PageTitle>Named Tuples</PageTitle>

<h1>Named Tuples Example</h1>

<NamedTupleChild Data="data" />

@code {
    private (int TheInteger, string TheString, bool TheBoolean) data = 
        new(999, "I aim to misbehave.", true);
}

Citation ©2005 Universal Pictures : Serenity (Nathan Fillion)

Les Tuples (documentation de l’API) sont pris en charge pour les paramètres de composant et les types RenderFragment. L’exemple de paramètre de composant suivant passe trois valeurs dans un Tuple :

RenderTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.Item1</li>
            <li>String: @Data?.Item2</li>
            <li>Boolean: @Data?.Item3</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int, string, bool)? Data { get; set; }
}

RenderTupleParent.razor:

@page "/render-tuple-parent"

<PageTitle>Render Tuple Parent</PageTitle>

<h1>Render Tuple Parent Example</h1>

<RenderTupleChild Data="data" />

@code {
    private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}

Les tuples nommés sont pris en charge, comme indiqué dans l’exemple suivant :

NamedTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.TheInteger</li>
            <li>String: @Data?.TheString</li>
            <li>Boolean: @Data?.TheBoolean</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}

NamedTuples.razor:

@page "/named-tuples"

<PageTitle>Named Tuples</PageTitle>

<h1>Named Tuples Example</h1>

<NamedTupleChild Data="data" />

@code {
    private (int TheInteger, string TheString, bool TheBoolean) data = 
        new(999, "I aim to misbehave.", true);
}

Citation ©2005 Universal Pictures : Serenity (Nathan Fillion)

Les Tuples (documentation de l’API) sont pris en charge pour les paramètres de composant et les types RenderFragment. L’exemple de paramètre de composant suivant passe trois valeurs dans un Tuple :

RenderTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.Item1</li>
            <li>String: @Data?.Item2</li>
            <li>Boolean: @Data?.Item3</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int, string, bool)? Data { get; set; }
}

RenderTupleParent.razor:

@page "/render-tuple-parent"

<h1>Render Tuple Parent</h1>

<RenderTupleChild Data="data" />

@code {
    private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}

Les tuples nommés sont pris en charge, comme indiqué dans l’exemple suivant :

RenderNamedTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.TheInteger</li>
            <li>String: @Data?.TheString</li>
            <li>Boolean: @Data?.TheBoolean</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}

RenderNamedTupleParent.razor:

@page "/render-named-tuple-parent"

<h1>Render Named Tuple Parent</h1>

<RenderNamedTupleChild Data="data" />

@code {
    private (int TheInteger, string TheString, bool TheBoolean) data = 
        new(999, "I aim to misbehave.", true);
}

Citation ©2005 Universal Pictures : Serenity (Nathan Fillion)

Paramètres de routage

Les composants peuvent spécifier des paramètres de routage dans le modèle de routage de la directive @page. Le routeur Blazor utilise des paramètres de routage pour remplir les paramètres de composant correspondants.

RouteParameter1.razor:

@page "/route-parameter-1/{text}"

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

<p>Blazor is @Text!</p>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

<p>Blazor is @Text!</p>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}

Pour obtenir plus d’informations, consultez la section des Paramètres de routage du routage et de la navigation ASP.NET Core Blazor. Les paramètres de routage facultatifs sont également pris en charge et abordés dans la même section. Pour obtenir plus d’informations sur les paramètres de routage catch-all ({*pageRoute}), qui capturent les chemins dans les nombreuses limites du dossier, consultez la section Paramètres de routage catch-all du routage et de la navigation ASP.NET Core Blazor.

Pour obtenir plus d’informations, consultez la section des Paramètres de routage du routage et de la navigation ASP.NET Core Blazor. Les paramètres de routage facultatifs ne sont pas pris en charge. Par conséquent, deux directives @page sont requises (consultez la section Paramètres de routage pour obtenir plus d’informations). Pour obtenir plus d’informations sur les paramètres de routage catch-all ({*pageRoute}), qui capturent les chemins dans les nombreuses limites du dossier, consultez la section Paramètres de routage catch-all du routage et de la navigation ASP.NET Core Blazor.

Avertissement

Avec la compression, qui est activée par défaut, évitez de créer des composants côté serveur interactifs (authentifiés/autorisés) sécurisés qui affichent des données en provenance de sources non approuvées. Les sources non approuvées incluent les paramètres de routage, les chaînes de requête, les données de JS l’interopérabilité, et toute autre source de données qu’un utilisateur tiers peut contrôler (bases de données, services externes). Pour plus d’informations, consultez Conseils pour ASP.NET Core BlazorSignalR et Conseils d’atténuation des menaces pour le rendu interactif côté serveur de ASP.NET Core Blazor.

Fragments de rendu de contenu enfant

Les composants peuvent définir le contenu d’un autre composant. Le composant d’affectation fournit le contenu entre les balises d’ouverture et de fermeture du composant enfant.

Dans l’exemple suivant, le composant RenderFragmentChild a un paramètre de composant ChildContent qui représente un segment de l’interface utilisateur rendu en tant que RenderFragment. La position de ChildContent dans le balisage Razor du composant correspond à l’emplacement où le contenu est rendu dans la sortie HTML finale.

RenderFragmentChild.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}

Important

La propriété qui reçoit le contenu RenderFragment doit être nommée ChildContent par convention.

Les rappels d’événements ne sont pas pris en charge pour RenderFragment.

Le composant suivant fournit du contenu pour générer le rendu de RenderFragmentChild. Pour cela, le contenu est placé à l’intérieur des balises d’ouverture et de fermeture du composant enfant.

RenderFragments.razor:

@page "/render-fragments"

<PageTitle>Render Fragments</PageTitle>

<h1>Render Fragments Example</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragments.razor:

@page "/render-fragments"

<PageTitle>Render Fragments</PageTitle>

<h1>Render Fragments Example</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

Des fragments de rendu sont utilisés pour générer le rendu du contenu enfant dans les applications Blazor et sont décrits avec des exemples dans les articles et sections d’article suivants :

Remarque

Les composants Razor intégrés du framework Blazor utilisent la même convention de paramètre de composant ChildContent pour définir leur contenu. Vous pouvez voir les composants qui définissent le contenu enfant en recherchant le nom de propriété de paramètre de composant ChildContent dans la documentation de l’API (filtre l’API avec le terme de recherche « ChildContent »).

Fragments de rendu pour une logique de rendu réutilisable

Vous pouvez employer des composants enfants dans le seul but de réutiliser la logique de rendu. Dans le bloc @code d’un composant quelconque, définissez un RenderFragment et générez le rendu du fragment à partir de n’importe quel emplacement autant de fois que nécessaire :

@RenderWelcomeInfo

<p>Render the welcome info a second time:</p>

@RenderWelcomeInfo

@code {
    private RenderFragment RenderWelcomeInfo =  @<p>Welcome to your new app!</p>;
}

Pour plus d’informations, consultez Réutiliser la logique de rendu.

Variables de boucle avec des paramètres de composant et du contenu enfant

Le rendu de composants à l’intérieur d’une boucle for nécessite une variable d’index local si la variable de boucle d’incrémentation est utilisée par les paramètres de composant ou le contenu enfant RenderFragment.

Considérez le composant suivant RenderFragmentChild2 qui a à la fois un paramètre de composant (Id) et un fragment de rendu pour afficher le contenu enfant (ChildContent).

RenderFragmentChild2.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content (@Id)</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public string? Id { get; set; }

    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}

Lors du rendu du composant RenderFragmentChild2 dans un composant parent, utilisez une variable d’index local (ct dans l’exemple suivant) au lieu de la variable de boucle (c) lors de l’attribution de la valeur du paramètre du composant et de la fourniture du contenu du composant enfant :

@for (int c = 1; c < 4; c++)
{
    var ct = c;

    <RenderFragmentChild2 Id="@($"Child{ct}")">
        Count: @ct
    </RenderFragmentChild2>
}

Vous pouvez également utiliser une boucle foreach avec Enumerable.Range à la place d’une boucle for.

@foreach (var c in Enumerable.Range(1, 3))
{
    <RenderFragmentChild2 Id="@($"Child{c}")">
        Count: @c
    </RenderFragmentChild2>
}

Capturer les références à des composants

Les références de composants permettent de référencer une instance de composant pour émettre des commandes. Pour capturer une référence de composant :

  • Ajoutez un attribut @ref au composant enfant.
  • Définissez un champ du même type que le composant enfant.

Quand le composant est rendu, le champ est rempli avec l’instance du composant. Vous pouvez ensuite appeler des méthodes .NET sur l’instance.

Considérez le composant ReferenceChild suivant qui journalise un message quand son ChildMethod est appelé.

ReferenceChild.razor:

@inject ILogger<ReferenceChild> Logger

@if (value > 0)
{
    <p>
        <code>value</code>: @value
    </p>
}

@code {
    private int value;

    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);

        this.value = value;
        StateHasChanged();
    }
}
@inject ILogger<ReferenceChild> Logger

@if (value > 0)
{
    <p>
        <code>value</code>: @value
    </p>
}

@code {
    private int value;

    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);

        this.value = value;
        StateHasChanged();
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}

Une référence de composant n’est remplie qu’après le rendu du composant et sa sortie inclut l’élément de ReferenceChild. Tant que le composant n’est pas rendu, il n’y a rien à référencer. N’essayez pas d’appeler une méthode de composant référencée directement à un gestionnaire d’événements (comme @onclick="childComponent!.ChildMethod(5)"), car la variable de référence peut ne pas être attribuée au moment où l’événement click est attribué.

Pour manipuler les références de composant une fois le rendu du composant terminé, utilisez les méthodes OnAfterRender ou OnAfterRenderAsync.

L’exemple suivant utilise le composant ReferenceChild précédent.

ReferenceParent.razor:

@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod() => childComponent2!.ChildMethod(5);
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod() => childComponent2!.ChildMethod(5);
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}

Bien que la capture de références de composants utilise une syntaxe similaire à la capture de références d’éléments, il ne s’agit pas d’une fonctionnalité d’interopérabilité JavaScript. Les références de composants ne sont pas passées au code JavaScript. Les références de composants sont uniquement utilisées dans le code .NET.

Important

N’utilisez pas de références de composants pour muter l’état des composants enfants. Au lieu de cela, utilisez des paramètres de composant déclaratifs normaux pour passer des données aux composants enfants. L’utilisation de paramètres de composant entraîne la regénération automatique du rendu des composants enfants au bon moment. Pour plus d’informations, consultez la section sur les paramètres de composant et l’article sur la liaison de données Blazor ASP.NET Core.

Appliquer un attribut

Des attributs peuvent être appliqués à des composants avec la directive @attribute. L’exemple suivant applique l’attribut [Authorize] à la classe du composant :

@page "/"
@attribute [Authorize]

Attributs d’élément HTML conditionnels et propriétés DOM

Blazor adopte les comportements généraux suivants :

  • Pour les attributs HTML, Blazor définit ou supprime l’attribut de manière conditionnelle en fonction de la valeur .NET. Si la valeur .NET est false ou null, l’attribut n’est pas défini ou est supprimé s’il était précédemment défini.
  • Pour les propriétés DOM, comme checked ou value, Blazor définit la propriété DOM en fonction de la valeur .NET. Si la valeur .NET est false ou null, la propriété DOM est réinitialisée sur une valeur par défaut.

Les attributs de syntaxe Razor qui correspondent aux attributs HTML et ceux qui correspondent aux propriétés DOM restent non documentés, car c’est un détail d’implémentation susceptible de changer sans préavis.

Avertissement

Certains attributs HTML, comme aria-pressed, doivent avoir une valeur de chaîne « true » ou « false ». Comme ils nécessitent une valeur de chaîne et non une valeur booléenne, vous devez utiliser une valeur string .NET et non une valeur bool. Ces exigences sont définies par les API DOM du navigateur.

HTML brut

Les chaînes sont normalement rendues à l’aide de nœuds de texte DOM, ce qui signifie que le balisage qu’elles peuvent contenir est ignoré et traité comme du texte littéral. Pour générer le rendu de code HTML brut, wrappez le contenu HTML dans une valeur MarkupString. La valeur est analysée au format HTML ou SVG et insérée dans le DOM.

Warning

Le rendu de code HTML brut construit à partir d’une source non approuvée présente un risque de sécurité et doit toujours être évité.

L’exemple suivant montre comment utiliser le type MarkupString pour ajouter un bloc de contenu HTML statique à la sortie rendue d’un composant.

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

Modèles Razor

Les fragments de rendu peuvent être définis avec la syntaxe de modèle Razor pour définir un extrait de code d’interface utilisateur. Les modèles Razor utilisent le format suivant :

@<{HTML tag}>...</{HTML tag}>

L’exemple suivant montre comment spécifier les valeurs RenderFragment et RenderFragment<TValue> et générer le rendu de modèles directement dans un composant. Les fragments de rendu peuvent également être passés en tant qu’arguments aux composants basés sur un modèle.

RazorTemplate.razor:

@page "/razor-template"

<PageTitle>Razor Template</PageTitle>

<h1>Razor Template Example</h1>

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

<PageTitle>Razor Template</PageTitle>

<h1>Razor Template Example</h1>

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string Name { get; set; }
    }
}

Sortie rendue du code précédent :

<p>The time is 4/19/2021 8:54:46 AM.</p>
<p>Pet: Nutty Rex</p>

Les ressources statiques

Blazor suit la convention des applications ASP.NET Core pour les ressources statiques. Les ressources statiques se trouvent dans le dossier web root (wwwroot) du projet ou dans des dossiers sous le dossier wwwroot.

Utilisez un chemin relatif de base (/) pour faire référence à la racine web d’une ressource statique. Dans l’exemple suivant, logo.png se trouve physiquement dans le dossier {PROJECT ROOT}/wwwroot/images. {PROJECT ROOT} est la racine du projet de l’application.

<img alt="Company logo" src="/images/logo.png" />

Les composants ne prennent pas en charge la notation tilde-barre oblique (~/).

Pour plus d’informations sur la définition du chemin de base d’une application, consultez Héberger et déployer Blazor ASP.NET Core.

Tag Helpers non pris en charge dans les composants

Les Tag Helpers ne sont pas pris en charge dans les composants. Pour bénéficier d’une fonctionnalité de type Tag Helper dans Blazor, créez un composant avec la même fonctionnalité que le Tag Helper et utilisez le composant à la place.

Images SVG (Scalable Vector Graphics)

Étant donné que Blazor génère le rendu de code HTML, les images prises en charge par les navigateurs, notamment les images SVG (.svg), sont prises en charge avec la balise <img> :

<img alt="Example image" src="image.svg" />

De même, les images SVG sont prises en charge dans les règles CSS d’un fichier de feuille de style (.css) :

.element-class {
    background-image: url("image.svg");
}

Blazor prend en charge l’élément <foreignObject> pour afficher du code HTML arbitraire dans un SVG. Le balisage peut représenter du code HTML arbitraire, un RenderFragment ou un composant Razor.

L’exemple suivant illustre cette situation :

  • Affichage d’un string (@message).
  • Liaison bidirectionnelle avec un élément <input> et un champ value.
  • Composant Robot.
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black" 
        fill="none" />
    <foreignObject x="20" y="20" width="160" height="160">
        <p>@message</p>
    </foreignObject>
</svg>

<svg xmlns="http://www.w3.org/2000/svg">
    <foreignObject width="200" height="200">
        <label>
            Two-way binding:
            <input @bind="value" @bind:event="oninput" />
        </label>
    </foreignObject>
</svg>

<svg xmlns="http://www.w3.org/2000/svg">
    <foreignObject>
        <Robot />
    </foreignObject>
</svg>

@code {
    private string message = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
        "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

    private string? value;
}

Comportement de rendu des espaces blancs

À moins que la directive @preservewhitespace ne soit utilisée avec la valeur true, un espace blanc supplémentaire est supprimé dans les cas suivants :

  • Espace blanc de début ou de fin au sein d’un élément.
  • Espace blanc de début ou de fin au sein d’un paramètre RenderFragment/RenderFragment<TValue> (par exemple, contenu enfant passé à un autre composant).
  • Espace blanc précédant ou suivant un bloc de code C#, comme @if ou @foreach.

La suppression de l’espace blanc peut affecter la sortie rendue lors de l’utilisation d’une règle CSS, par exemple white-space: pre. Pour désactiver cette optimisation des performances et conserver l’espace blanc, effectuez l’une des actions suivantes :

  • Ajoutez la directive @preservewhitespace true en haut du fichier Razor (.razor) pour appliquer la préférence à un composant spécifique.
  • Ajoutez la directive @preservewhitespace true dans un fichier _Imports.razor pour appliquer la préférence à un sous-répertoire ou à l’ensemble du projet.

Dans la plupart des cas, aucune action n’est requise car les applications continuent généralement à se comporter normalement (mais plus rapidement). Si la suppression d’un espace blanc entraîne un problème de rendu pour un composant particulier, utilisez @preservewhitespace true dans ce composant pour désactiver cette optimisation.

L’espace blanc est conservé dans le balisage source d’un composant. Le texte d’espace blanc s’affiche uniquement dans le DOM du navigateur même si’n’y a aucun effet visuel.

Considérez le balisage du composant suivant :

<ul>
    @foreach (var item in Items)
    {
        <li>
            @item.Text
        </li>
    }
</ul>

L’exemple précédent génère le rendu de l’espace blanc inutile suivant :

  • En dehors du bloc de code @foreach.
  • Autour de l’élément <li>.
  • Autour de la sortie @item.Text.

Une liste de 100 éléments donne lieu à plus de 400 zones d’espaces blancs. Aucun des espaces blancs supplémentaires n’affecte visuellement la sortie rendue.

Lors du rendu du code HTML statique pour les composants, les espaces blancs à l’intérieur d’une balise ne sont pas conservés. Par exemple, affichez la sortie rendue de la balise <img> suivante dans un fichier Razor de composant (.razor) :

<img     alt="Example image"   src="img.png"     />

L’espace blanc n’est pas conservé du balisage précédent :

<img alt="Example image" src="img.png" />

Composant racine

Un composant Razor racine (composant racine) est le premier composant chargé d’une hiérarchie de composants créée par l’application.

Dans une application créée à partir du modèle de projet Blazor Web App, le composant App (App.razor) est spécifié comme composant racine par défaut par le paramètre de type déclaré pour l’appel à MapRazorComponents<TRootComponent> dans le fichier Program côté serveur. L’exemple suivant montre l’utilisation du composant App comme composant racine, qui est la valeur par défaut d’une application créée à partir du modèle de projet Blazor :

app.MapRazorComponents<App>();

Remarque

La création d’un composant racine interactif, tel que le composant App, n’est pas prise en charge.

Dans une application créée à partir du modèle de projet Blazor Server, le composant App (App.razor) est spécifié en tant que composant racine par défaut dans Pages/_Host.cshtml à l’aide du Tag Helper de composant :

<component type="typeof(App)" render-mode="ServerPrerendered" />

Dans une application créée à partir du modèle de projet Blazor WebAssembly, le composant App (App.razor) est créé en tant que composant racine par défaut dans le fichierProgram :

builder.RootComponents.Add<App>("#app");

Dans le code précédent, le sélecteur CSS, #app, indique que le composant App est spécifié pour le <div> dans wwwroot/index.html avec un id de app :

<div id="app">...</app>

Les applications MVC et Razor Pages peuvent également utiliser le Tag Helper de composant pour inscrire les composants racines rendus Blazor WebAssembly de manière statique :

<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />

Les composants rendus de manière statique peuvent uniquement être ajoutés à l’application. Ils ne peuvent pas être supprimés ou mis à jour par la suite.

Pour plus d'informations, reportez-vous aux ressources suivantes :