Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Questo articolo illustra come eseguire il flusso di dati da un componente predecessore Razor ai componenti discendenti.
I valori e i parametri a catena offrono un modo pratico per eseguire il flusso dei dati in una gerarchia di componenti da un componente predecessore a un numero qualsiasi di componenti discendenti. A differenza dei parametri component, i valori e i parametri a catena non richiedono un'assegnazione di attributo per ogni componente discendente in cui vengono utilizzati i dati. I valori e i parametri a catena consentono anche ai componenti di coordinarsi tra loro in una gerarchia di componenti.
Nota
Gli esempi di codice in questo articolo adottano tipi di riferimento nullable (NRT) e l'analisi statica dello stato null del compilatore .NET, supportati in ASP.NET Core in .NET 6 o versione successiva. Quando si prende di mira .NET 5 o versioni precedenti, rimuovere la designazione di tipo null (?
) dai tipi CascadingType?
, @ActiveTab?
, RenderFragment?
, ITab?
, TabSet?
e string?
negli esempi dell'articolo.
Valori a cascata a livello radice
I valori a catena a livello radice possono essere registrati per l'intera gerarchia dei componenti. Sono supportati valori e sottoscrizioni denominati a catena per le notifiche di aggiornamento.
La classe seguente viene usata negli esempi di questa sezione.
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; }
}
Le registrazioni seguenti vengono effettuate nel file dell'app Program
con AddCascadingValue:
-
Dalek
con un valore della proprietà perUnits
viene registrato come valore a catena fisso. - Una seconda
Dalek
registrazione con un valore di proprietà diverso perUnits
è denominata "AlphaGroup
".
builder.Services.AddCascadingValue(sp => new Dalek { Units = 123 });
builder.Services.AddCascadingValue("AlphaGroup", sp => new Dalek { Units = 456 });
Nel componente seguente Daleks
vengono visualizzati i valori a catena.
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]
public 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]
public Dalek? Dalek { get; set; }
[CascadingParameter(Name = "AlphaGroup")]
public Dalek? AlphaGroupDalek { get; set; }
}
Nell'esempio Dalek
seguente viene registrato come valore a catena usando CascadingValueSource<T>
, dove <T>
è il tipo . Il isFixed
flag indica se il valore è fisso. Se false
, tutti i destinatari vengono sottoscritti per le notifiche di aggiornamento. Le sottoscrizioni creano overhead e riducono le prestazioni, quindi impostate su isFixed
true
se il valore non cambia.
builder.Services.AddCascadingValue(sp =>
{
var dalek = new Dalek { Units = 789 };
var source = new CascadingValueSource<Dalek>(dalek, isFixed: false);
return source;
});
Avviso
La registrazione di un tipo di componente come valore a catena a livello radice non registra servizi aggiuntivi per il tipo o consente l'attivazione del servizio nel componente.
Gestire i servizi necessari separatamente dai valori a catena, registrandoli separatamente dal tipo a catena.
Evitare di usare AddCascadingValue per registrare un tipo di componente come valore a catena. Al contrario, eseguire il <Router>...</Router>
wrapping di Routes
nel componente (Components/Routes.razor
) con il componente e adottare il rendering sul lato server interattivo globale (SSR interattivo). Per un esempio, vedere la sezione relativa al CascadingValue
componente .
Valori a cascata a livello radice con notifiche
La chiamata NotifyChangedAsync a inviare notifiche di aggiornamento può essere usata per segnalare a più Razor sottoscrittori di componenti che un valore a catena è cambiato. Le notifiche non sono possibili per i sottoscrittori che adottano il rendering statico lato server (SSR statico), quindi i sottoscrittori devono adottare una modalità di rendering interattiva.
Nell'esempio seguente:
-
NotifyingDalek
implementa INotifyPropertyChanged per notificare ai client che un valore della proprietà è stato modificato. Quando laUnits
proprietà è impostata, il PropertyChangedEventHandler (PropertyChanged
) viene richiamato. - Il
SetUnitsToOneThousandAsync
metodo può essere attivato dai sottoscrittori per impostareUnits
su 1.000 con un ritardo di elaborazione simulato.
Tenere presente nel codice di produzione che qualsiasi modifica dello stato (qualsiasi modifica del valore della proprietà della classe) causa il ri-rendering di tutti i componenti sottoscritti, indipendentemente da quale parte dello stato venga utilizzata. È consigliabile creare classi granulari, che vengono propagate separatamente con sottoscrizioni specifiche per garantire che solo i componenti sottoscritti a una parte specifica dello stato dell'applicazione siano interessati dalle modifiche.
Nota
Per una Blazor Web App soluzione costituita da progetti server e client (.Client
), il file seguente NotifyingDalek.cs
viene inserito nel .Client
progetto.
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;
}
}
Il seguente CascadingStateServiceCollectionExtensions
crea un CascadingValueSource<TValue> da un tipo che implementa INotifyPropertyChanged.
Nota
Per una Blazor Web App soluzione costituita da progetti server e client (.Client
), il file seguente CascadingStateServiceCollectionExtensions.cs
viene inserito nel .Client
progetto.
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;
}
}
}
Il tipo PropertyChangedEventHandler (HandlePropertyChanged
) chiama il metodo di CascadingValueSource<TValue>NotifyChangedAsync per notificare ai sottoscrittori che il valore a cascata è stato modificato. L'oggetto Task viene rimosso quando si chiama NotifyChangedAsync perché la chiamata rappresenta solo la durata dell'invio al contesto sincrono. Le eccezioni vengono gestite internamente indirizzandole al renderer nel contesto del componente che ha generato l'eccezione durante la ricezione dell'aggiornamento. Si tratta dello stesso modo in cui le eccezioni vengono elaborate con un CascadingValue<TValue>oggetto , che non riceve notifiche sulle eccezioni che si verificano all'interno dei destinatari delle notifiche. Il gestore eventi viene disconnesso nel Dispose
metodo per evitare una perdita di memoria.
Nel file Program
, NotifyingDalek
viene passato per creare un CascadingValueSource<TValue> con un valore iniziale Unit
di 888 unità.
builder.Services.AddNotifyingCascadingValue(new NotifyingDalek() { Units = 888 });
Nota
Per una Blazor Web App soluzione costituita da progetti server e client (.Client
), il codice sopra menzionato viene inserito nel file Program
di ciascun progetto.
Il componente seguente viene usato per illustrare come modificare il valore di NotifyingDalek.Units
notifica ai sottoscrittori.
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]
public 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();
}
}
}
Per illustrare più notifiche degli abbonati, il componente seguente DaleksMain
renderizza tre Daleks
componenti. Quando viene aggiornato il numero di unità (Units
) di un Dalek
componente, gli altri due Dalek
sottoscrittori dei componenti vengono aggiornati.
DaleksMain.razor
:
@page "/daleks-main"
<PageTitle>Daleks Main</PageTitle>
<h1>Daleks Main</h1>
<Daleks />
<Daleks />
<Daleks />
Aggiungere un collegamento di navigazione al componente DaleksMain
in 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>
Poiché in questo esempio il tipo di CascadingValueSource<TValue> (NotifyingDalek
) è un tipo di classe, è possibile soddisfare praticamente qualsiasi requisito della specifica delle funzionalità di gestione dello stato. Tuttavia, le sottoscrizioni creano overhead e riducono le prestazioni, quindi confrontano le prestazioni di questo approccio nella tua app e confrontalo con altri approcci di gestione dello stato prima di adottarlo in un'app di produzione con risorse di elaborazione e memoria limitate.
Qualsiasi modifica dello stato (qualsiasi variazione del valore di una proprietà della classe) fa sì che tutti i componenti registrati vengano rindirizzati, indipendentemente dalla parte dello stato utilizzata. Evitare di creare una singola classe di grandi dimensioni che rappresenta l'intero stato dell'applicazione globale. Creare invece classi granulari e propagarle separatamente con sottoscrizioni specifiche ai parametri a catena, assicurandosi che solo i componenti sottoscritti a una parte specifica dello stato dell'applicazione siano interessati dalle modifiche.
Componente CascadingValue
Un componente predecessore fornisce un valore a catena usando il componente del Blazor framework, che esegue il CascadingValue
wrapping di un sottoalbero di una gerarchia di componenti e fornisce un singolo valore a tutti i componenti all'interno del relativo sottoalbero.
Nell'esempio seguente viene illustrato il flusso delle informazioni sul tema nella gerarchia dei componenti per fornire una classe di stile CSS ai pulsanti nei componenti figlio.
La classe C# seguente ThemeInfo
specifica le informazioni sul tema.
Nota
Per gli esempi in questa sezione, lo spazio dei nomi dell'app è BlazorSample
. Quando si sperimenta il codice nella propria app di esempio, modificare lo spazio dei nomi dell'app nello spazio dei nomi dell'app di esempio.
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; }
}
}
Il componente di layout seguente specifica le informazioni sul tema (ThemeInfo
) come valore a catena per tutti i componenti che costituiscono il corpo del layout della Body proprietà.
ButtonClass
viene assegnato un valore di btn-success
, che è uno stile pulsante Bootstrap. Qualsiasi componente discendente nella gerarchia dei componenti può usare la ButtonClass
proprietà tramite il ThemeInfo
valore a catena.
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" };
}
Blazor Web Apps forniscono approcci alternativi per i valori a catena che si applicano più ampiamente all'app rispetto all'arredamento tramite un unico file di layout:
Eseguire il wrapping del markup del
Routes
componente in unCascadingValue
componente per specificare i dati come valore a catena per tutti i componenti dell'app.Nell'esempio seguente vengono propagati i
ThemeInfo
dati dalRoutes
componente .Routes.razor
:<CascadingValue Value="theme"> <Router ...> ... </Router> </CascadingValue> @code { private ThemeInfo theme = new() { ButtonClass = "btn-success" }; }
Nota
Il wrapping dell'istanza
Routes
delApp
componente nel componente (Components/App.razor
) con unCascadingValue
componente non è supportato.Specificare un valore a catena a livello radice come servizio chiamando il AddCascadingValue metodo di estensione nel generatore di raccolte di servizi.
Nell'esempio seguente vengono propagati i
ThemeInfo
dati dalProgram
file .Program.cs
builder.Services.AddCascadingValue(sp => new ThemeInfo() { ButtonClass = "btn-primary" });
Per altre informazioni, vedere le sezioni seguenti di questo articolo:
Attributo [CascadingParameter]
Per usare i valori a catena, i componenti discendenti dichiarano parametri a catena usando l'attributo [CascadingParameter]
. I valori a catena sono associati a parametri a catena per tipo. La propagazione di più valori dello stesso tipo è descritta nella sezione Cascade multiple values più avanti in questo articolo.
Il componente seguente associa il ThemeInfo
valore a catena a un parametro a catena, facoltativamente usando lo stesso nome di ThemeInfo
. Il parametro viene usato per impostare la classe CSS per il Increment Counter (Themed)
pulsante.
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]
protected 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]
protected 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]
protected 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]
protected 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]
protected 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]
protected ThemeInfo ThemeInfo { get; set; }
private void IncrementCount()
{
currentCount++;
}
}
Analogamente a un parametro di componente normale, i componenti che accettano un parametro a catena vengono rirenderati quando viene modificato il valore a catena. Ad esempio, la configurazione di un'istanza del tema diversa causa il ripristino del ThemedCounter
componente dalla sezione del CascadingValue
componente .
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 può essere usato per indicare che un parametro a catena non cambia dopo l'inizializzazione.
Valori/parametri a catena e limiti della modalità di rendering
I parametri a catena non passano i dati tra i limiti della modalità di rendering:
Le sessioni interattive vengono eseguite in un contesto diverso rispetto alle pagine che usano il rendering statico lato server (SSR statico). Non è necessario che il server che produce la pagina sia anche lo stesso computer che ospita alcune sessioni successive di Interactive Server, incluso per i componenti WebAssembly in cui il server è un computer diverso per il client. Il vantaggio del rendering statico lato server (SSR statico) è quello di ottenere le prestazioni complete del rendering HTML senza stato puro.
Lo stato che supera il limite tra il rendering statico e interattivo deve essere serializzabile. I componenti sono oggetti arbitrari che fanno riferimento a una vasta catena di altri oggetti, tra cui il renderer, il contenitore DI e ogni istanza del servizio di inserimento delle dipendenze. È necessario fare in modo esplicito che lo stato venga serializzato da SSR statico per renderlo disponibile nei componenti visualizzati in modo interattivo successivo. Vengono adottati due approcci:
- Tramite il Blazor framework, i parametri passati attraverso un ssrio statico al limite di rendering interattivo vengono serializzati automaticamente se sono serializzabili in JSON o viene generato un errore.
- Lo stato archiviato in
PersistentComponentState
viene serializzato e ripristinato automaticamente se è serializzabile in JSON o viene generato un errore.
I parametri a catena non sono serializzabili in JSON perché i modelli di utilizzo tipici per i parametri a catena sono in qualche modo simili ai servizi di inserimento delle dipendenze. Spesso ci sono varianti specifiche della piattaforma di parametri a catena, quindi sarebbe inutili per gli sviluppatori se il framework impedisse agli sviluppatori di avere versioni specifiche del server o versioni specifiche di WebAssembly. Inoltre, molti valori di parametro a catena in generale non sono serializzabili, quindi sarebbe poco pratico aggiornare le app esistenti se si dovesse interrompere l'uso di tutti i valori dei parametri nonerializzabili a catena.
Raccomandazioni:
Se è necessario rendere disponibile lo stato per tutti i componenti interattivi come parametro a catena, è consigliabile usare valori a catena a livello radice o valori a catena a livello radice con notifiche. È disponibile un modello factory e l'app può generare valori aggiornati dopo l'avvio dell'app. I valori a catena a livello radice sono disponibili per tutti i componenti, inclusi i componenti interattivi, poiché vengono elaborati come servizi di inserimento delle dipendenze.
Per gli autori di librerie di componenti, è possibile creare un metodo di estensione per i consumer di libreria in modo simile al seguente:
builder.Services.AddLibraryCascadingParameters();
Indicare agli sviluppatori di chiamare il metodo di estensione. Si tratta di un'alternativa audio per indicare loro di aggiungere un
<RootComponent>
componente nel componenteMainLayout
.
Più valori a catena
Per propagare più valori dello stesso tipo all'interno dello stesso sottoalbero, specificare una stringa univoca Name per ogni CascadingValue
componente e i relativi attributi.[CascadingParameter]
Nell'esempio seguente due CascadingValue
componenti si sovrapporno a istanze diverse di CascadingType
:
<CascadingValue Value="parentCascadeParameter1" Name="CascadeParam1">
<CascadingValue Value="ParentCascadeParameter2" Name="CascadeParam2">
...
</CascadingValue>
</CascadingValue>
@code {
private CascadingType? parentCascadeParameter1;
[Parameter]
public CascadingType? ParentCascadeParameter2 { get; set; }
}
In un componente discendente, i parametri a catena ricevono i valori a catena dal componente predecessore da Name:
@code {
[CascadingParameter(Name = "CascadeParam1")]
protected CascadingType? ChildCascadeParameter1 { get; set; }
[CascadingParameter(Name = "CascadeParam2")]
protected CascadingType? ChildCascadeParameter2 { get; set; }
}
Passare i dati attraverso una gerarchia di componenti
I parametri a catena consentono anche ai componenti di passare i dati in una gerarchia di componenti. Si consideri l'esempio di set di schede dell'interfaccia utente seguente, in cui un componente del set di schede gestisce una serie di singole schede.
Nota
Per gli esempi in questa sezione, lo spazio dei nomi dell'app è BlazorSample
. Quando si sperimenta il codice nella propria app di esempio, modificare lo spazio dei nomi dell'app di esempio nello spazio dei nomi dell'app di esempio.
Creare un'interfaccia ITab
implementata da schede in una cartella denominata UIInterfaces
.
UIInterfaces/ITab.cs
:
using Microsoft.AspNetCore.Components;
namespace BlazorSample.UIInterfaces;
public interface ITab
{
RenderFragment ChildContent { get; }
}
Nota
Per altre informazioni su RenderFragment, vedere Razor di base.
Il componente seguente TabSet
gestisce un set di schede. I componenti del set di Tab
schede, creati più avanti in questa sezione, specificano gli elementi di elenco () per l'elenco (<li>...</li>
<ul>...</ul>
).
I componenti figlio Tab
non vengono passati in modo esplicito come parametri a TabSet
. I componenti figlio Tab
fanno invece parte del contenuto figlio di TabSet
. Tuttavia, l'TabSet
necessita ancora di un riferimento a ogni componente Tab
in modo che possa eseguire il rendering delle intestazioni e della scheda attiva. Per abilitare questo coordinamento senza richiedere codice aggiuntivo, il componente TabSet
può fornire se stesso come valore a catena che viene quindi prelevato dai componenti Tab
discendenti.
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();
}
}
}
I componenti discendenti Tab
acquisisce l'oggetto che lo contiene TabSet
come parametro a catena. I Tab
componenti si aggiungono alla TabSet
coordinata e per impostare la scheda attiva.
Tab.razor
:
@using BlazorSample.UIInterfaces
@implements ITab
<li>
<a @onclick="ActivateTab" class="nav-link @TitleCssClass" role="button">
@Title
</a>
</li>
@code {
[CascadingParameter]
public 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);
}
}
Il componente seguente ExampleTabSet
usa il TabSet
componente , che contiene tre Tab
componenti.
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;
}