Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Remarque
Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 10 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 support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.
Cet article explique comment faire passer le flux de données d’un composant Razor ancêtre aux composants descendants.
Les valeurs et paramètres en cascade offrent un moyen pratique de faire passer le flux de données vers le bas d’une hiérarchie de composants, d’un composant ancêtre vers un nombre quelconque de composants descendants. Contrairement aux paramètres de composant, les valeurs et paramètres en cascade ne nécessitent pas d’affectation d’attribut pour chaque composant descendant où les données sont consommées. Les valeurs et paramètres en cascade permettent également aux composants de se coordonner entre eux au sein d’une hiérarchie de composants.
Remarque
Les exemples de code dans cet article adoptent les types référence null (NRT, nullable reference types) et l'analyse statique de l'état nul du compilateur .NET qui sont pris en charge dans ASP.NET Core 6 ou une version ultérieure. Lorsque vous ciblez .NET 5 ou une version antérieure, supprimez la désignation de type Null (?) des types CascadingType?, @ActiveTab?, RenderFragment?, ITab?, TabSet? et string? dans les exemples de l'article.
Valeurs en cascade du niveau racine
Les valeurs en cascade au niveau racine peuvent être inscrites pour la hiérarchie complète des composants. Les valeurs et abonnements nommés en cascade pour les notifications de mise à jour sont pris en charge.
La classe suivante est utilisée dans les exemples de cette section.
Dalek.cs :
// "Dalek" ©Terry Nation https://www.imdb.com/name/nm0622334/
// "Doctor Who" ©BBC https://www.bbc.co.uk/programmes/b006q2x0
namespace BlazorSample;
public class Dalek
{
public int Units { get; set; }
}
// "Dalek" ©Terry Nation https://www.imdb.com/name/nm0622334/
// "Doctor Who" ©BBC https://www.bbc.co.uk/programmes/b006q2x0
namespace BlazorSample;
public class Dalek
{
public int Units { get; set; }
}
Les inscriptions suivantes sont effectuées dans le fichier Program de l’application avec AddCascadingValue :
- Avec une valeur de propriété pour
Dalek,Unitsest inscrit comme valeur en cascade fixe. - Une deuxième inscription
Dalekavec une valeur de propriété différente pourUnitsest nommée «AlphaGroup».
builder.Services.AddCascadingValue(sp => new Dalek { Units = 123 });
builder.Services.AddCascadingValue("AlphaGroup", sp => new Dalek { Units = 456 });
Le composant Daleks suivant affiche les valeurs en cascade.
Daleks.razor :
@page "/daleks"
<PageTitle>Daleks</PageTitle>
<h1>Root-level Cascading Value Example</h1>
<ul>
<li>Dalek Units: @Dalek?.Units</li>
<li>Alpha Group Dalek Units: @AlphaGroupDalek?.Units</li>
</ul>
<p>
Dalek© <a href="https://www.imdb.com/name/nm0622334/">Terry Nation</a><br>
Doctor Who© <a href="https://www.bbc.co.uk/programmes/b006q2x0">BBC</a>
</p>
@code {
[CascadingParameter]
private Dalek? Dalek { get; set; }
[CascadingParameter(Name = "AlphaGroup")]
public Dalek? AlphaGroupDalek { get; set; }
}
@page "/daleks"
<PageTitle>Daleks</PageTitle>
<h1>Root-level Cascading Value Example</h1>
<ul>
<li>Dalek Units: @Dalek?.Units</li>
<li>Alpha Group Dalek Units: @AlphaGroupDalek?.Units</li>
</ul>
<p>
Dalek© <a href="https://www.imdb.com/name/nm0622334/">Terry Nation</a><br>
Doctor Who© <a href="https://www.bbc.co.uk/programmes/b006q2x0">BBC</a>
</p>
@code {
[CascadingParameter]
private Dalek? Dalek { get; set; }
[CascadingParameter(Name = "AlphaGroup")]
public Dalek? AlphaGroupDalek { get; set; }
}
Dans l’exemple suivant, Dalek est inscrit comme valeur en cascade à l’aide de CascadingValueSource<T>, avec <T> comme type. L’indicateur isFixed signale si la valeur est corrigée. Si false, tous les destinataires sont abonnés pour les notifications de mise à jour. Les abonnements créent des surcharges et réduisent les performances. Définissez donc isFixed sur true, si la valeur ne change pas.
builder.Services.AddCascadingValue(sp =>
{
var dalek = new Dalek { Units = 789 };
var source = new CascadingValueSource<Dalek>(dalek, isFixed: false);
return source;
});
Avertissement
L’inscription d’un type de composant en tant que valeur en cascade de niveau racine ne permet pas d'enregistrer des services supplémentaires pour le type ni d’autoriser l’activation du service dans le composant.
Traitez les services requis séparément des valeurs en cascade, en les inscrivant séparément du type en cascade.
Évitez d’utiliser AddCascadingValue pour inscrire un type de composant en tant que valeur en cascade. Au lieu de cela, enveloppez le <Router>...</Router> dans le composant Routes (Components/Routes.razor) avec le composant et adoptez le rendu interactif global côté serveur (SSR interactif). Pour obtenir un exemple, consultez la section CascadingValueComposant.
Valeurs en cascade au niveau racine avec des notifications
L’appel NotifyChangedAsync pour émettre des notifications de mise à jour peut être utilisé pour signaliser à plusieurs abonnés aux composants qu’une valeur en cascade a changé. Les notifications ne sont pas possibles pour les abonnés qui adoptent le rendu côté serveur statique (SSR statique), de sorte que les abonnés doivent adopter un mode de rendu interactif.
Dans l’exemple suivant :
-
NotifyingDalekimplémente INotifyPropertyChanged pour informer les clients qu'une valeur de propriété a changé. Lorsque laUnitspropriété est définie, le PropertyChangedEventHandler (PropertyChanged) est appelé. - La
SetUnitsToOneThousandAsyncméthode peut être déclenchée par les abonnés pour définirUnitssur 1 000 avec un délai de traitement simulé.
N’oubliez pas que tout changement d’état (toute modification de valeur de propriété de la classe) entraîne le raffichage de tous les composants abonnés, peu importe la partie de l'état utilisée. Nous vous recommandons de créer des classes granulaires, de les cascader séparément avec des abonnements spécifiques pour vous assurer que seuls les composants abonnés à une partie spécifique de l’état de l’application sont affectés par les modifications.
Remarque
Pour une Blazor Web App solution composée de projets serveur et client (.Client), le fichier suivant NotifyingDalek.cs est placé dans le .Client projet.
NotifyingDalek.cs :
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class NotifyingDalek : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private int units;
public int Units
{
get => units;
set
{
if (units != value)
{
units = value;
OnPropertyChanged();
}
}
}
protected virtual void OnPropertyChanged(
[CallerMemberName] string? propertyName = default)
=> PropertyChanged?.Invoke(this, new(propertyName));
public async Task SetUnitsToOneThousandAsync()
{
// Simulate a three second delay in processing
await Task.Delay(3000);
Units = 1000;
}
}
L’exemple suivant CascadingStateServiceCollectionExtensions crée un CascadingValueSource<TValue> à partir d'un type qui implémente INotifyPropertyChanged.
Remarque
Pour une Blazor Web App solution composée de projets serveur et client (.Client), le fichier suivant CascadingStateServiceCollectionExtensions.cs est placé dans le .Client projet.
CascadingStateServiceCollectionExtensions.cs :
using System.ComponentModel;
using Microsoft.AspNetCore.Components;
namespace Microsoft.Extensions.DependencyInjection;
public static class CascadingStateServiceCollectionExtensions
{
public static IServiceCollection AddNotifyingCascadingValue<T>(
this IServiceCollection services, T state, bool isFixed = false)
where T : INotifyPropertyChanged
{
return services.AddCascadingValue<T>(sp =>
{
return new CascadingStateValueSource<T>(state, isFixed);
});
}
private sealed class CascadingStateValueSource<T>
: CascadingValueSource<T>, IDisposable where T : INotifyPropertyChanged
{
private readonly T state;
private readonly CascadingValueSource<T> source;
public CascadingStateValueSource(T state, bool isFixed = false)
: base(state, isFixed = false)
{
this.state = state;
source = new CascadingValueSource<T>(state, isFixed);
this.state.PropertyChanged += HandlePropertyChanged;
}
private void HandlePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
_ = NotifyChangedAsync();
}
public void Dispose()
{
state.PropertyChanged -= HandlePropertyChanged;
}
}
}
Le type PropertyChangedEventHandler (HandlePropertyChanged) appelle la méthode CascadingValueSource<TValue> de NotifyChangedAsync pour avertir les abonnés que la valeur de cascade a changé. Le Task est ignoré lors de l'appel de NotifyChangedAsync, car l'appel représente uniquement la durée de l'envoi dans le contexte synchrone. Les exceptions sont gérées en interne en les envoyant vers le renderer dans le contexte du composant ayant généré l'erreur lors de la réception de la mise à jour. Il s’agit de la même façon que les exceptions sont traitées avec un CascadingValue<TValue>, qui n’est pas informé des exceptions qui se produisent à l’intérieur des destinataires de notification. Le gestionnaire d’événements est déconnecté dans la Dispose méthode pour empêcher une fuite de mémoire.
Dans le fichier Program, NotifyingDalek est passé pour créer un CascadingValueSource<TValue> avec une valeur initiale de Unit de 888 unités :
builder.Services.AddNotifyingCascadingValue(new NotifyingDalek() { Units = 888 });
Remarque
Pour une solution Blazor Web App composée de projets de serveur et de client (.Client), le code précédent est placé dans le fichier Program de chaque projet.
Le composant suivant est utilisé pour démontrer comment la modification de la valeur de NotifyingDalek.Units avertit les abonnés.
Daleks.razor :
<h2>Daleks component</h2>
<div>
<b>Dalek Units:</b> @Dalek?.Units
</div>
<div>
<label>
<span style="font-weight:bold">New Unit Count:</span>
<input @bind="dalekCount" />
</label>
<button @onclick="Update">Update</button>
</div>
<div>
<button @onclick="SetOneThousandUnits">Set Units to 1,000</button>
</div>
<p>
Dalek© <a href="https://www.imdb.com/name/nm0622334/">Terry Nation</a><br>
Doctor Who© <a href="https://www.bbc.co.uk/programmes/b006q2x0">BBC</a>
</p>
@code {
private int dalekCount;
[CascadingParameter]
private NotifyingDalek? Dalek { get; set; }
private void Update()
{
if (Dalek is not null)
{
Dalek.Units = dalekCount;
dalekCount = 0;
}
}
private async Task SetOneThousandUnits()
{
if (Dalek is not null)
{
await Dalek.SetUnitsToOneThousandAsync();
}
}
}
Pour illustrer plusieurs notifications d’abonné, le composant suivant DaleksMain affiche trois Daleks composants. Lorsque le nombre d’unités (Units) d’un Dalek composant est mis à jour, les deux Dalek autres abonnés aux composants sont mis à jour.
DaleksMain.razor :
@page "/daleks-main"
<PageTitle>Daleks Main</PageTitle>
<h1>Daleks Main</h1>
<Daleks />
<Daleks />
<Daleks />
Ajoutez un lien de navigation dans le composant DaleksMain de NavMenu.razor.
<div class="nav-item px-3">
<NavLink class="nav-link" href="daleks-main">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Daleks
</NavLink>
</div>
Étant donné que le CascadingValueSource<TValue>type de cet exemple (NotifyingDalek) est un type de classe, vous pouvez répondre à pratiquement n’importe quelle spécification de fonctionnalité de gestion d’état. Toutefois, les abonnements créent des frais généraux et réduisent les performances. Par conséquent, évaluez les performances de cette approche dans votre application et comparez-les à d’autres approches de gestion d’état avant de l’adopter dans une application de production avec des ressources de traitement et de mémoire limitées.
Toute modification de l’état (toute modification de valeur de propriété de la classe) entraîne la réutilisation de tous les composants abonnés, quelle que soit la partie de l’état qu’ils utilisent. Évitez de créer une seule classe volumineuse représentant l’ensemble de l’état d’application global. Au lieu de cela, créez des classes granulaires et cascadez-les séparément avec des abonnements spécifiques aux paramètres en cascade, ce qui garantit que seuls les composants abonnés à une partie spécifique de l’état de l’application sont affectés par les modifications.
CascadingValue (composant)
Un composant ancêtre fournit une valeur en cascade à l’aide du composant Blazor du framework CascadingValue, qui inclut dans un wrapper une sous-arborescence d’une hiérarchie de composants, et fournit une seule valeur à tous les composants de sa sous-arborescence.
L’exemple suivant montre le flux des informations de thème vers le bas de la hiérarchie des composants pour fournir une classe de style CSS aux boutons des composants enfants.
La classe C# ThemeInfo suivante spécifie les informations relatives au thème.
Remarque
Pour les exemples de cette section, l’espace de noms de l’application est BlazorSample. Quand vous testez le code dans votre propre exemple d’application, remplacez l’espace de noms de l’application par l’espace de noms de votre exemple d’application.
ThemeInfo.cs :
namespace BlazorSample;
public class ThemeInfo
{
public string? ButtonClass { get; set; }
}
namespace BlazorSample;
public class ThemeInfo
{
public string? ButtonClass { get; set; }
}
namespace BlazorSample.UIThemeClasses;
public class ThemeInfo
{
public string? ButtonClass { get; set; }
}
namespace BlazorSample.UIThemeClasses;
public class ThemeInfo
{
public string? ButtonClass { get; set; }
}
namespace BlazorSample.UIThemeClasses
{
public class ThemeInfo
{
public string ButtonClass { get; set; }
}
}
namespace BlazorSample.UIThemeClasses
{
public class ThemeInfo
{
public string ButtonClass { get; set; }
}
}
Le composant de disposition suivant spécifie les informations de thème (ThemeInfo) sous la forme d’une valeur en cascade pour tous les composants qui constituent le corps de disposition de la propriété Body.
ButtonClass se voit affecter la valeur btn-success, qui est un style de bouton Bootstrap. Tout composant descendant dans la hiérarchie de composants peut utiliser la propriété ButtonClass via la valeur en cascade ThemeInfo.
MainLayout.razor :
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
<CascadingValue Value="theme">
<article class="content px-4">
@Body
</article>
</CascadingValue>
</main>
</div>
<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="." class="reload">Reload</a>
<span class="dismiss">🗙</span>
</div>
@code {
private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
<CascadingValue Value="theme">
<article class="content px-4">
@Body
</article>
</CascadingValue>
</main>
</div>
<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
@code {
private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<CascadingValue Value="@theme">
<article class="content px-4">
@Body
</article>
</CascadingValue>
</main>
</div>
@code {
private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<CascadingValue Value="@theme">
<div class="content px-4">
@Body
</div>
</CascadingValue>
</main>
</div>
@code {
private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<CascadingValue Value="@theme">
<div class="content px-4">
@Body
</div>
</CascadingValue>
</div>
</div>
@code {
private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<CascadingValue Value="theme">
<div class="content px-4">
@Body
</div>
</CascadingValue>
</div>
@code {
private ThemeInfo theme = new ThemeInfo { ButtonClass = "btn-success" };
}
Les Blazor Web App proposent des approches alternatives pour les valeurs en cascade qui s’appliquent plus largement à l’application que la fourniture de ces valeurs via un seul fichier de présentation :
Encapsulez le balisage du composant
Routesdans un composantCascadingValuepour spécifier les données comme valeur en cascade pour tous les composants de l’application.L’exemple suivant cascade les données
ThemeInfodu composantRoutes.Routes.razor:<CascadingValue Value="theme"> <Router ...> ... </Router> </CascadingValue> @code { private ThemeInfo theme = new() { ButtonClass = "btn-success" }; }Remarque
L’intégration de l’instance de composant
Routesdans le composantApp(Components/App.razor) avec un composantCascadingValuen’est pas pris en charge.Spécifiez une valeur en cascade du niveau racine en tant que service en appelant la méthode d’extension AddCascadingValue sur le générateur de collection de services.
L’exemple suivant cascade les données
ThemeInfodu fichierProgram.Program.csbuilder.Services.AddCascadingValue(sp => new ThemeInfo() { ButtonClass = "btn-primary" });
Pour plus d’informations, consultez les sections suivantes de cette article :
Attribut [CascadingParameter]
Pour utiliser des valeurs en cascade, les composants descendants déclarent les paramètres en cascade à l’aide de l’attribut [CascadingParameter]. Les valeurs en cascade sont liées aux paramètres en cascade par type. La création d’une cascade de plusieurs valeurs du même type est traitée dans la section Créer une cascade de plusieurs valeurs plus loin dans cet article.
Le private modificateur d’accès est recommandé pour les paramètres en cascade, car le paramètre doit être limité à une utilisation uniquement dans la classe du composant dans la plupart des cas. Lorsque la sous-classe est requise, utilisez le modificateur d’accès protected .
Le composant suivant lie la valeur en cascade ThemeInfo à un paramètre en cascade, en utilisant éventuellement le même nom que ThemeInfo. Le paramètre permet de définir la classe CSS du bouton Increment Counter (Themed).
ThemedCounter.razor :
@page "/themed-counter"
<PageTitle>Themed Counter</PageTitle>
<h1>Themed Counter Example</h1>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">
Increment Counter (Unthemed)
</button>
</p>
<p>
<button
class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)"
@onclick="IncrementCount">
Increment Counter (Themed)
</button>
</p>
@code {
private int currentCount = 0;
[CascadingParameter]
private ThemeInfo? ThemeInfo { get; set; }
private void IncrementCount() => currentCount++;
}
@page "/themed-counter"
<PageTitle>Themed Counter</PageTitle>
<h1>Themed Counter Example</h1>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">
Increment Counter (Unthemed)
</button>
</p>
<p>
<button
class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)"
@onclick="IncrementCount">
Increment Counter (Themed)
</button>
</p>
@code {
private int currentCount = 0;
[CascadingParameter]
private ThemeInfo? ThemeInfo { get; set; }
private void IncrementCount() => currentCount++;
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses
<h1>Themed Counter</h1>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">
Increment Counter (Unthemed)
</button>
</p>
<p>
<button
class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)"
@onclick="IncrementCount">
Increment Counter (Themed)
</button>
</p>
@code {
private int currentCount = 0;
[CascadingParameter]
private ThemeInfo? ThemeInfo { get; set; }
private void IncrementCount()
{
currentCount++;
}
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses
<h1>Themed Counter</h1>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">
Increment Counter (Unthemed)
</button>
</p>
<p>
<button
class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)"
@onclick="IncrementCount">
Increment Counter (Themed)
</button>
</p>
@code {
private int currentCount = 0;
[CascadingParameter]
private ThemeInfo? ThemeInfo { get; set; }
private void IncrementCount()
{
currentCount++;
}
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses
<h1>Themed Counter</h1>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">
Increment Counter (Unthemed)
</button>
</p>
<p>
<button class="btn @ThemeInfo.ButtonClass" @onclick="IncrementCount">
Increment Counter (Themed)
</button>
</p>
@code {
private int currentCount = 0;
[CascadingParameter]
private ThemeInfo ThemeInfo { get; set; }
private void IncrementCount()
{
currentCount++;
}
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses
<h1>Themed Counter</h1>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">
Increment Counter (Unthemed)
</button>
</p>
<p>
<button class="btn @ThemeInfo.ButtonClass" @onclick="IncrementCount">
Increment Counter (Themed)
</button>
</p>
@code {
private int currentCount = 0;
[CascadingParameter]
private ThemeInfo ThemeInfo { get; set; }
private void IncrementCount()
{
currentCount++;
}
}
À l’image d’un paramètre de composant classique, les composants qui acceptent un paramètre en cascade sont réaffichés quand la valeur en cascade change. Par exemple, la configuration d’une autre instance de thème entraîne un nouveau rendu du composant ThemedCounter décrit dans la section Composant CascadingValue.
MainLayout.razor :
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<CascadingValue Value="theme">
<article class="content px-4">
@Body
</article>
</CascadingValue>
<button @onclick="ChangeToDarkTheme">Dark mode</button>
</main>
@code {
private ThemeInfo theme = new() { ButtonClass = "btn-success" };
private void ChangeToDarkTheme()
{
theme = new() { ButtonClass = "btn-secondary" };
}
}
CascadingValue<TValue>.IsFixed peut être utilisé pour indiquer qu’un paramètre en cascade ne change pas après son initialisation.
Valeurs/paramètres en cascade et limites du mode de rendu
Les paramètres en cascade ne passent pas de données entre les limites du mode de rendu :
Les sessions interactives s’exécutent dans un contexte différent de celui des pages qui utilisent un rendu statique côté serveur (SSR statique). Il n’est pas nécessaire que le serveur produisant la page soit la même machine que celle qui héberge une session ultérieure du serveur interactif, y compris pour les composants WebAssembly où le serveur est une machine différente pour le client. L’avantage du rendu statique côté serveur (SSR statique) est de bénéficier de tous les niveaux de performance du rendu HTML sans état.
L’état qui traverse la limite entre le rendu statique et le rendu interactif doit être sérialisable. Les composants sont des objets arbitraires qui référencent une vaste chaîne d’autres objets, y compris le renderer, le conteneur d’injection de dépendances et chaque instance du service d’injection de dépendances. Vous devez explicitement faire en sorte que l’état soit sérialisé à partir d’un SSR statique pour qu’il soit disponible dans les composants interactifs suivants. Deux approches sont adoptées :
- Avec le framework Blazor, les paramètres transmis d’un SSR statique à une limite de rendu interactif sont sérialisés automatiquement s’ils sont sérialisables en JSON. Sinon, une erreur est renvoyée.
- L’état stocké dans Persistent Component State est sérialisé et récupéré automatiquement s’il est JSON-sérialisable, ou qu’une erreur est générée.
Les paramètres en cascade ne sont pas sérialisables en JSON, car les modèles d’utilisation classiques des paramètres en cascade sont similaires aux services d’injection de dépendance. Il existe souvent des variantes des paramètres en cascade qui sont spécifiques à la plateforme : il serait donc inutile pour les développeurs que le framework les empêche d’avoir des versions spécifiques au serveur interactif ou des versions spécifiques au WebAssembly. En outre, de nombreuses valeurs de paramètres en cascade ne sont généralement pas sérialisables : il serait donc impraticable de mettre à jour des applications existantes si vous deviez arrêter d’utiliser toutes les valeurs de paramètre en cascade non sérialisables.
Recommandations :
Si vous devez rendre l’état disponible pour tous les composants interactifs en tant que paramètre en cascade, nous vous recommandons d’utiliser des valeurs en cascade au niveau racine ou des valeurs en cascade au niveau racine avec des notifications. Un modèle de fabrique est disponible et l’application peut émettre des valeurs mises à jour après son démarrage. Les valeurs en cascade au niveau racine sont disponibles pour tous les composants, y compris les composants interactifs, car elles sont traitées en tant que services d’injection de dépendances.
Pour les créateurs de bibliothèques de composants, vous pouvez créer une méthode d’extension pour les consommateurs de bibliothèques, similaire à ceci :
builder.Services.AddLibraryCascadingParameters();Demandez aux développeurs d’appeler votre méthode d’extension. Cela constitue une bonne alternative à la demande d’ajout d’un composant
<RootComponent>dans leur composantMainLayout.
Créer une cascade de plusieurs valeurs
Pour créer une cascade de plusieurs valeurs du même type dans la même sous-arborescence, fournissez une seule chaîne Name à chaque composant CascadingValue ainsi qu’à leurs attributs [CascadingParameter] correspondants.
Dans l’exemple suivant, deux composants CascadingValue font passer en cascade différentes instances de CascadingType :
<CascadingValue Value="parentCascadeParameter1" Name="CascadeParam1">
<CascadingValue Value="ParentCascadeParameter2" Name="CascadeParam2">
...
</CascadingValue>
</CascadingValue>
@code {
private CascadingType? parentCascadeParameter1;
[Parameter]
public CascadingType? ParentCascadeParameter2 { get; set; }
}
Dans un composant descendant, les paramètres en cascade reçoivent leurs valeurs en cascade du composant ancêtre par Name :
@code {
[CascadingParameter(Name = "CascadeParam1")]
protected CascadingType? ChildCascadeParameter1 { get; set; }
[CascadingParameter(Name = "CascadeParam2")]
protected CascadingType? ChildCascadeParameter2 { get; set; }
}
Passer des données dans une hiérarchie de composants
Les paramètres en cascade permettent également aux composants de passer des données au sein d’une hiérarchie de composants. Prenons l’exemple suivant d’un ensemble d’onglets d’IU, où un composant d’ensemble d’onglets gère une série d’onglets individuels.
Remarque
Pour les exemples de cette section, l’espace de noms de l’application est BlazorSample. Quand vous testez le code dans votre propre exemple d’application, remplacez l’espace de noms par l’espace de noms de votre exemple d’application.
Créez une interface ITab que les onglets implémentent dans un dossier nommé UIInterfaces.
UIInterfaces/ITab.cs :
using Microsoft.AspNetCore.Components;
namespace BlazorSample.UIInterfaces;
public interface ITab
{
RenderFragment ChildContent { get; }
}
Remarque
Pour plus d’informations sur RenderFragment, consultez Composants ASP.NET Core Razor.
Le composant TabSet suivant gère un ensemble d’onglets. Les composants Tab de l’ensemble d’onglets, créés plus loin dans cette section, fournissent les éléments de liste (<li>...</li>) de la liste (<ul>...</ul>).
Les composants Tab enfants ne sont pas explicitement passés en tant que paramètres à TabSet. À la place, les composants Tab enfants font partie du contenu enfant de TabSet. Toutefois, il TabSet a toujours besoin d’une référence à chaque Tab composant afin qu’il puisse afficher les en-têtes et l’onglet actif. Pour activer cette coordination sans nécessiter de code supplémentaire, le TabSet composant peut se fournir en tant que valeur en cascade qui est ensuite captée par les composants descendants Tab.
TabSet.razor :
@using BlazorSample.UIInterfaces
<!-- Display the tab headers -->
<CascadingValue Value="this">
<ul class="nav nav-tabs">
@ChildContent
</ul>
</CascadingValue>
<!-- Display body for only the active tab -->
<div class="nav-tabs-body p-4">
@ActiveTab?.ChildContent
</div>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
public ITab? ActiveTab { get; private set; }
public void AddTab(ITab tab)
{
if (ActiveTab is null)
{
SetActiveTab(tab);
}
}
public void SetActiveTab(ITab tab)
{
if (ActiveTab != tab)
{
ActiveTab = tab;
StateHasChanged();
}
}
}
Les composants Tab descendants capturent le TabSet conteneur en tant que paramètre en cascade. Les composants Tab s’ajoutent à TabSet, et se coordonnent pour définir l’onglet actif.
Tab.razor :
@using BlazorSample.UIInterfaces
@implements ITab
<li>
<a @onclick="ActivateTab" class="nav-link @TitleCssClass" role="button">
@Title
</a>
</li>
@code {
[CascadingParameter]
private TabSet? ContainerTabSet { get; set; }
[Parameter]
public string? Title { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private string? TitleCssClass =>
ContainerTabSet?.ActiveTab == this ? "active" : null;
protected override void OnInitialized()
{
ContainerTabSet?.AddTab(this);
}
private void ActivateTab()
{
ContainerTabSet?.SetActiveTab(this);
}
}
Le composant ExampleTabSet suivant utilise le composant TabSet, qui contient trois composants Tab.
ExampleTabSet.razor :
@page "/example-tab-set"
<TabSet>
<Tab Title="First tab">
<h4>Greetings from the first tab!</h4>
<label>
<input type="checkbox" @bind="showThirdTab" />
Toggle third tab
</label>
</Tab>
<Tab Title="Second tab">
<h4>Hello from the second tab!</h4>
</Tab>
@if (showThirdTab)
{
<Tab Title="Third tab">
<h4>Welcome to the disappearing third tab!</h4>
<p>Toggle this tab from the first tab.</p>
</Tab>
}
</TabSet>
@code {
private bool showThirdTab;
}