Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Tento článek vysvětluje, jak tok dat z nadřazené Razor komponenty do sestupných komponent.
Kaskádové hodnoty a parametry poskytují pohodlný způsob, jak tok dat v hierarchii komponent z nadřazené komponenty do libovolného počtu sestupných komponent. Na rozdíl od parametrů komponent nevyžadují kaskádové hodnoty a parametry přiřazení atributů pro každou sestupnou komponentu, ve které jsou data spotřebována. Kaskádové hodnoty a parametry také umožňují komponentám vzájemně koordinovat hierarchii komponent.
Poznámka:
Příklady kódu v tomto článku přijímají referenční typy s možnou hodnotou null (NRT) a statickou analýzu stavu null-stav kompilátoru .NET, které jsou podporovány v ASP.NET Core v .NET 6 nebo novější. Při cílení na .NET 5 nebo starší odeberte označení typu null z typů ?, CascadingType?, @ActiveTab?, RenderFragment?, ITab? a TabSet? v příkladech článku.
Kaskádové hodnoty na kořenové úrovni
Kaskádové hodnoty kořenové úrovně lze zaregistrovat pro celou hierarchii komponent. Podporují se pojmenované kaskádové hodnoty a odběry pro oznámení o aktualizacích.
V příkladech této části se používá následující třída.
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; }
}
V souboru aplikace Program jsou provedeny následující registrace:AddCascadingValue
-
Daleks hodnotou vlastnosti proUnitsje registrován jako pevná kaskádová hodnota. - Druhá
Dalekregistrace s jinou hodnotou vlastnosti máUnitsnázev "AlphaGroup".
builder.Services.AddCascadingValue(sp => new Dalek { Units = 123 });
builder.Services.AddCascadingValue("AlphaGroup", sp => new Dalek { Units = 456 });
Následující Daleks komponenta zobrazuje kaskádové hodnoty.
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; }
}
V následujícím příkladu Dalek je registrován jako kaskádová hodnota pomocí CascadingValueSource<T>, kde <T> je typ. Příznak isFixed označuje, jestli je hodnota pevná. Pokud falsejsou všichni příjemci přihlášení k odběru oznámení o aktualizacích. Předplatná vytvářejí režii a snižují výkon, takže pokud isFixed se hodnota nezmění, nastavte true ji.
builder.Services.AddCascadingValue(sp =>
{
var dalek = new Dalek { Units = 789 };
var source = new CascadingValueSource<Dalek>(dalek, isFixed: false);
return source;
});
Upozorňující
Registrace typu komponenty jako kaskádové hodnoty kořenové úrovně neregistruje další služby pro typ nebo povolení aktivace služby v komponentě.
Zacházejte s požadovanými službami odděleně od kaskádových hodnot a zaregistrujte je odděleně od kaskádového typu.
AddCascadingValue Vyhněte se registraci typu komponenty jako kaskádové hodnoty. Místo toho zabalte <Router>...</Router> komponentu Routes (Components/Routes.razor) komponentou a přijměte globální interaktivní vykreslování na straně serveru (interaktivní SSR). Příklad najdete v CascadingValue části komponent .
Kaskádové hodnoty na úrovni kořene s upozorněními
Volání NotifyChangedAsync na oznámení o aktualizaci problému lze použít k signalizaci více Razor odběratelů komponent, že se změnila kaskádová hodnota. Oznámení nejsou možná pro předplatitele používající statické vykreslování na straně serveru, takže předplatitelé musí použít interaktivní režim vykreslování.
V následujícím příkladu:
-
NotifyingDalekimplementuje INotifyPropertyChanged pro upozornění klientů, že se změnila hodnota vlastnosti. Když je vlastnostUnitsnastavena, PropertyChangedEventHandler je vyvolána (PropertyChanged). - Tuto
SetUnitsToOneThousandAsyncmetodu můžou aktivovat předplatitelé, aby nastaviliUnitshodnotu 1 000 se simulovaným zpožděním zpracování.
Mějte na paměti pro produkční kód, že jakákoli změna stavu (jakákoli změna hodnoty vlastnosti třídy) způsobí, že všechny zaregistrované komponenty se znovu vykreslí, nezávisle na tom, kterou část stavu využívají. Doporučujeme vytvářet podrobné třídy, které je kaskádují samostatně s konkrétními předplatnými, aby se zajistilo, že změny ovlivní jenom komponenty, které se přihlásí k odběru určité části stavu aplikace.
Poznámka:
Blazor Web App Pro řešení skládající se z projektů serveru a klienta (.Client) se do NotifyingDalek.cs projektu umístí následující .Client soubor.
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;
}
}
Následující CascadingStateServiceCollectionExtensions příkaz vytvoří CascadingValueSource<TValue> z typu, který implementuje INotifyPropertyChanged.
Poznámka:
Blazor Web App Pro řešení skládající se z projektů serveru a klienta (.Client) se do CascadingStateServiceCollectionExtensions.cs projektu umístí následující .Client soubor.
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;
}
}
}
Typ PropertyChangedEventHandler (HandlePropertyChanged) volá metodu CascadingValueSource<TValue> objektu NotifyChangedAsync k upozornění odběratelů na změnu kaskádové hodnoty. Při volání Task se NotifyChangedAsync zahodí, protože volání představuje pouze dobu trvání předání do synchronního kontextu. Výjimky jsou zpracovávány interně tak, že jsou v rámci kontextu komponentu, která je vyvolala při přijetí aktualizace, odesílány do rendereru. Toto je stejný způsob, jakým se výjimky zpracovávají pomocí CascadingValue<TValue>, který není upozorněn na výjimky, ke kterým dochází uvnitř příjemců oznámení. Obslužná rutina události je v Dispose metodě odpojena, aby se zabránilo úniku paměti.
V souboru Program se předá NotifyingDalek k vytvoření CascadingValueSource<TValue> s počáteční hodnotou Unit 888 jednotek.
builder.Services.AddNotifyingCascadingValue(new NotifyingDalek() { Units = 888 });
Poznámka:
Blazor Web App U řešení skládajícího se z projektů serveru a klienta (.Client) se předchozí kód umístí do souboru každého projektuProgram.
Následující komponenta slouží k předvedení toho, jak změna hodnoty NotifyingDalek.Units upozorňuje odběratele.
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();
}
}
}
Pokud chcete předvést oznámení více odběratelů, následující DaleksMain komponenta vykreslí tři Daleks komponenty. Při aktualizaci počtu jednotek (Units) jedné Dalek komponenty se aktualizují ostatní dva Dalek odběratelé komponent.
DaleksMain.razor:
@page "/daleks-main"
<PageTitle>Daleks Main</PageTitle>
<h1>Daleks Main</h1>
<Daleks />
<Daleks />
<Daleks />
Přidejte navigační odkaz na komponentu DaleksMain v 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>
CascadingValueSource<TValue>Vzhledem k tomu, že typ v tomto příkladu (NotifyingDalek) je typ třídy, můžete splnit prakticky jakýkoli požadavek na specifikaci funkce správy stavu. Předplatná ale vytvářejí režijní náklady a snižují výkon, takže proveďte srovnávací testy výkonu tohoto přístupu ve vaší aplikaci a porovnejte ho s jinými přístupy správy stavu , než je přijmete v produkční aplikaci s omezenými prostředky zpracování a paměti.
Jakákoli změna stavu (jakákoli změna hodnoty vlastnosti třídy) způsobí, že se všechny předplacené komponenty znovu zobrazí bez ohledu na to, kterou část stavu používají. Vyhněte se vytváření jedné velké třídy představující celý globální stav aplikace. Místo toho vytvořte podrobné třídy a kaskádujte je samostatně s konkrétními předplatnými a kaskádovými parametry a zajistěte, aby změny ovlivnily pouze komponenty, které jsou odebírané do určité části stavu aplikace.
CascadingValue komponenta
Nadřazená komponenta poskytuje kaskádovou hodnotu pomocí Blazor komponenty architektury CascadingValue , která zabalí podstrom hierarchie komponent a poskytuje jednu hodnotu všem komponentám v jeho podstromu.
Následující příklad ukazuje tok informací o motivu v hierarchii komponent, aby poskytoval třídu stylů CSS tlačítkům v podřízených komponentách.
ThemeInfo Následující třída jazyka C# určuje informace o motivu.
Poznámka:
V příkladech v této části je BlazorSampleobor názvů aplikace . Při experimentování s kódem ve vlastní ukázkové aplikaci změňte obor názvů aplikace na obor názvů ukázkové aplikace.
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; }
}
}
Následující komponenta rozložení určuje informace o motivu (ThemeInfo) jako kaskádovou hodnotu pro všechny komponenty, které tvoří tělo Body rozložení vlastnosti.
ButtonClass je přiřazena hodnota btn-success, což je bootstrap styl tlačítka. Libovolná sestupná komponenta v hierarchii komponent může tuto vlastnost použít ButtonClass prostřednictvím ThemeInfo kaskádové hodnoty.
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 poskytují alternativní přístupy k kaskádovým hodnotám, které se v aplikaci používají obecněji než jejich vybavení prostřednictvím jednoho souboru rozložení:
Zabalte kód
Routeskomponenty doCascadingValuekomponenty a určete data jako kaskádovou hodnotu pro všechny komponenty aplikace.Následující příklad kaskáduje
ThemeInfodata zRouteskomponenty.Routes.razor:<CascadingValue Value="theme"> <Router ...> ... </Router> </CascadingValue> @code { private ThemeInfo theme = new() { ButtonClass = "btn-success" }; }Poznámka:
RoutesZabalení instance komponenty doAppkomponenty (Components/App.razor) komponentouCascadingValuese nepodporuje.Zadejte kaskádovou hodnotu kořenové úrovně jako službu voláním AddCascadingValue metody rozšíření v tvůrci kolekce služeb.
Následující příklad kaskáduje
ThemeInfodata zeProgramsouboru.Program.csbuilder.Services.AddCascadingValue(sp => new ThemeInfo() { ButtonClass = "btn-primary" });
Další informace najdete v následujících částech tohoto článku:
Atribut [CascadingParameter]
Chcete-li použít kaskádové hodnoty, sestupné komponenty deklarují kaskádové parametry pomocí atributu[CascadingParameter]. Kaskádové hodnoty jsou vázané na kaskádové parametry podle typu. Kaskádové více hodnot stejného typu je popsáno v části Kaskádové více hodnot dále v tomto článku.
private Modifikátor přístupu se doporučuje pro kaskádové parametry, protože parametr by měl být vymezen pro použití pouze ve třídě komponenty ve většině případů. Pokud je požadováno podtřídění, použijte protected modifikátor přístupu.
Následující komponenta ThemeInfo vytvoří vazbu kaskádové hodnoty na kaskádový parametr, volitelně pomocí stejného názvu ThemeInfo. Parametr slouží k nastavení třídy CSS pro Increment Counter (Themed) tlačítko.
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++;
}
}
Podobně jako u běžného parametru komponenty se komponenty, které přijímají kaskádový parametr, změní při změně kaskádové hodnoty znovu. Například konfigurace jiné instance motivu způsobí ThemedCounter , že se komponenta z oddílu CascadingValue komponenty znovu vymění.
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 lze použít k označení, že se kaskádový parametr po inicializaci nezmění.
Kaskádové hodnoty/parametry a hranice režimu vykreslování
Kaskádové parametry nepředávají data přes hranice režimu vykreslování:
Interaktivní relace se spouštějí v jiném kontextu než stránky, které používají vykreslování na straně statického serveru (static SSR). Není nutné, aby server, který vytváří stránku, byl dokonce stejný počítač, který hostuje některé pozdější relace Interaktivního serveru, včetně komponent WebAssembly, kde je server jiným počítačem s klientem. Výhodou statického vykreslování na straně serveru (static SSR) je získání plného výkonu čistě bezstavového vykreslování HTML.
Stav překračující hranice mezi statickým a interaktivním vykreslováním musí být serializovatelný. Komponenty jsou libovolné objekty, které odkazují na rozsáhlý řetězec jiných objektů, včetně rendereru, kontejneru DI a každé instance služby DI. Musíte explicitně způsobit serializaci stavu ze statického SSR, aby byl dostupný v následných interaktivně vykreslených komponentách. Přijímají se dva přístupy:
- Blazor Prostřednictvím architektury se parametry předávané přes statickou SSR do interaktivní hranice vykreslování serializují automaticky, pokud jsou serializovatelné ve formátu JSON nebo dojde k chybě.
- Stav uložený ve stavu trvalé komponenty se serializuje a obnoví se automaticky, pokud je serializovatelný ve formátu JSON nebo dojde k chybě.
Kaskádové parametry nejsou serializovatelné ve formátu JSON, protože typické vzory použití kaskádových parametrů jsou trochu podobné službám DI. Často existují varianty kaskádových parametrů specifické pro platformu, takže by pro vývojáře bylo neužitečné, kdyby architektura zastavila vývojáře v tom, aby měli verze specifické pro server nebo webAssembly specifické verze. Mnoho kaskádových hodnot parametrů obecně není serializovatelné, takže by bylo nepraktické aktualizovat existující aplikace, pokud byste museli přestat používat všechny neserializovatelné kaskádové hodnoty parametrů.
Doporučení:
Pokud potřebujete zpřístupnit stav pro všechny interaktivní komponenty jako kaskádový parametr, doporučujeme použít kaskádové hodnoty kořenové úrovně nebo kaskádové hodnoty kořenové úrovně s oznámeními. Model továrny je k dispozici a aplikace může po spuštění aplikace generovat aktualizované hodnoty. Kaskádové hodnoty na kořenové úrovni jsou k dispozici pro všechny komponenty, včetně interaktivních komponent, protože se zpracovávají jako služby DI.
Pro autory knihoven komponent můžete vytvořit metodu rozšíření pro uživatele knihovny podobně jako v následujícím příkladu:
builder.Services.AddLibraryCascadingParameters();Dejte vývojářům pokyn, aby volali metodu rozšíření. Jedná se o zvukovou alternativu, která jim dává pokyn, aby do své
<RootComponent>komponenty přidali komponentuMainLayout.
Kaskádové více hodnot
Pokud chcete kaskádovat více hodnot stejného typu ve stejném podstromu, zadejte jedinečný Name řetězec pro každou CascadingValue komponentu a jejich odpovídající [CascadingParameter] atributy.
V následujícím příkladu dvě CascadingValue komponenty kaskádují různé instance CascadingType:
<CascadingValue Value="parentCascadeParameter1" Name="CascadeParam1">
<CascadingValue Value="ParentCascadeParameter2" Name="CascadeParam2">
...
</CascadingValue>
</CascadingValue>
@code {
private CascadingType? parentCascadeParameter1;
[Parameter]
public CascadingType? ParentCascadeParameter2 { get; set; }
}
V potomkové komponentě přijímají kaskádové parametry jejich kaskádové hodnoty z nadřazené komponenty Name:
@code {
[CascadingParameter(Name = "CascadeParam1")]
protected CascadingType? ChildCascadeParameter1 { get; set; }
[CascadingParameter(Name = "CascadeParam2")]
protected CascadingType? ChildCascadeParameter2 { get; set; }
}
Předávání dat napříč hierarchií komponent
Kaskádové parametry také umožňují komponentám předávat data napříč hierarchií komponent. Představte si následující příklad sady karet uživatelského rozhraní, kde komponenta sady karet udržuje řadu jednotlivých karet.
Poznámka:
V příkladech v této části je BlazorSampleobor názvů aplikace . Při experimentování s kódem ve vlastní ukázkové aplikaci změňte obor názvů na obor názvů ukázkové aplikace.
Vytvořte ITab rozhraní, které karty implementují ve složce s názvem UIInterfaces.
UIInterfaces/ITab.cs:
using Microsoft.AspNetCore.Components;
namespace BlazorSample.UIInterfaces;
public interface ITab
{
RenderFragment ChildContent { get; }
}
Poznámka:
Další informace o RenderFragmentkomponentách RazorASP.NET Core.
Následující TabSet komponenta udržuje sadu karet. Komponenty sady Tab karet, které jsou vytvořeny později v této části, zadejte položky seznamu (<li>...</li>) pro seznam (<ul>...</ul>).
Podřízené Tab komponenty nejsou explicitně předány jako parametry .TabSet Místo toho jsou podřízené Tab komponenty součástí podřízeného TabSetobsahu souboru . Stále však TabSet potřebuje odkaz na každou komponentu Tab, aby mohl vykreslit záhlaví a aktivní záložku. Aby byla tato koordinace možná bez nutnosti dalšího kódu, může se komponenta TabSet poskytnout jako kaskádová hodnota, kterou pak přebírají podřízené komponenty 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();
}
}
}
Komponenty Tab potomků zachycují obsahující TabSet jako kaskádový parametr. Komponenty Tab se přidají do TabSet a souřadnice pro nastavení aktivní karty.
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);
}
}
Následující ExampleTabSet komponenta používá komponentu TabSet , která obsahuje tři Tab komponenty.
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;
}