Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Artikel ini menjelaskan cara mengalirkan data dari komponen leluhur Razor ke komponen keturunan.
Nilai dan parameter berskala menyediakan cara mudah untuk mengalirkan data ke hierarki komponen dari komponen leluhur ke sejumlah komponen keturunan. Tidak seperti parameter Komponen, nilai dan parameter berskala tidak memerlukan penetapan atribut untuk setiap komponen turunan tempat data digunakan. Nilai dan parameter berskala juga memungkinkan komponen untuk berkoordinasi satu sama lain di seluruh hierarki komponen.
Catatan
Contoh kode dalam artikel ini mengadopsi jenis referensi nullable (NRTs) dan .NET compiler null-state static analysis, yang didukung di ASP.NET Core di .NET 6 atau yang lebih baru. Saat menargetkan .NET 5 atau yang lebih lama, hapus penunjukan jenis null (?
) dari CascadingType?
, @ActiveTab?
, RenderFragment?
, ITab?
, TabSet?
, dan string?
dalam contoh artikel.
Nilai berskala tingkat akar
Nilai kaskading tingkat akar dapat didaftarkan untuk seluruh hierarki komponen. Nilai dan langganan berskala bernama untuk pemberitahuan pembaruan didukung.
Kelas berikut digunakan dalam contoh bagian ini.
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; }
}
Pendaftaran berikut dibuat dalam file aplikasi Program
dengan AddCascadingValue:
-
Dalek
dengan nilai properti untukUnits
didaftarkan sebagai nilai kaskading tetap. - Pendaftaran kedua
Dalek
dengan nilai properti yang berbeda untukUnits
diberi nama "AlphaGroup
".
builder.Services.AddCascadingValue(sp => new Dalek { Units = 123 });
builder.Services.AddCascadingValue("AlphaGroup", sp => new Dalek { Units = 456 });
Komponen berikut Daleks
menampilkan nilai berskala.
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; }
}
Dalam contoh berikut, Dalek
terdaftar sebagai nilai berskala menggunakan CascadingValueSource<T>
, di mana <T>
adalah jenisnya. Bendera isFixed
menunjukkan apakah nilai diperbaiki. Jika false
, semua penerima berlangganan pemberitahuan pembaruan. Langganan membuat overhead dan mengurangi performa, jadi atur isFixed
ke true
jika nilai tidak berubah.
builder.Services.AddCascadingValue(sp =>
{
var dalek = new Dalek { Units = 789 };
var source = new CascadingValueSource<Dalek>(dalek, isFixed: false);
return source;
});
Peringatan
Mendaftarkan jenis komponen sebagai nilai kaskading tingkat akar tidak mendaftarkan layanan tambahan untuk jenis atau mengizinkan aktivasi layanan dalam komponen.
Perlakukan layanan yang diperlukan secara terpisah dari nilai kaskading, mendaftarkannya secara terpisah dari jenis berskala.
Hindari menggunakan AddCascadingValue untuk mendaftarkan jenis komponen sebagai nilai berskala. Sebagai gantinya <Router>...</Router>
, bungkus dalam Routes
komponen (Components/Routes.razor
) dengan komponen dan adopsi penyajian sisi server interaktif global (SSR interaktif). Misalnya, lihat bagian CascadingValue
komponen .
Nilai tingkat dasar berlapis dengan pemberitahuan
Panggilan NotifyChangedAsync untuk mengeluarkan pemberitahuan pembaruan dapat digunakan untuk memberi sinyal kepada beberapa Razor pelanggan komponen bahwa nilai berkala telah berubah. Pemberitahuan tidak dimungkinkan untuk pelanggan yang menggunakan server-side rendering statis (SSR), sehingga pelanggan harus menggunakan mode render interaktif.
Pada contoh berikut:
-
NotifyingDalek
INotifyPropertyChanged mengimplementasikan untuk memberi tahu klien bahwa nilai properti telah berubah. Ketika propertiUnits
diatur, maka PropertyChangedEventHandler (PropertyChanged
) akan dipanggil. - Metode
SetUnitsToOneThousandAsync
ini dapat dipicu oleh pelanggan langganan untuk mengaturUnits
menjadi 1.000 dengan penundaan pemrosesan yang disimulasikan.
Perlu diingat untuk kode produksi aplikasi bahwa setiap perubahan dalam state (setiap perubahan nilai properti kelas) menyebabkan semua komponen yang berlangganan dirender ulang, terlepas dari bagian state mana yang mereka gunakan. Sebaiknya buat kelas terperinci, mengkaskadenya secara terpisah dengan langganan tertentu untuk memastikan bahwa hanya komponen yang berlangganan bagian spesifik dari status aplikasi yang dipengaruhi oleh perubahan.
Catatan
Untuk solusi yang Blazor Web App terdiri dari proyek server dan klien (.Client
), file berikut NotifyingDalek.cs
ditempatkan dalam proyek .Client
.
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;
}
}
Berikut CascadingStateServiceCollectionExtensions
membuat CascadingValueSource<TValue> dari tipe yang mengimplementasikan INotifyPropertyChanged.
Catatan
Untuk solusi yang Blazor Web App terdiri dari proyek server dan klien (.Client
), file berikut CascadingStateServiceCollectionExtensions.cs
ditempatkan dalam proyek .Client
.
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;
}
}
}
Jenis PropertyChangedEventHandler (HandlePropertyChanged
) memanggil metode CascadingValueSource<TValue> milik NotifyChangedAsync untuk memberi tahu pengamat bahwa nilai kaskade telah berubah.
Task dibuang saat memanggil NotifyChangedAsync karena panggilan hanya mewakili durasi pengiriman ke konteks sinkron. Pengecualian ditangani secara internal dengan mengirimkannya ke perender dalam konteks komponen mana pun yang dilemparkan saat menerima pembaruan. Ini adalah cara yang sama seperti pengecualian diproses dengan CascadingValue<TValue>, yang tidak diberi tahu tentang pengecualian yang terjadi di dalam penerima notifikasi. Penangan kejadian terputus dalam metode Dispose
untuk mencegah kebocoran memori.
Dalam file Program
, NotifyingDalek
diteruskan untuk membuat CascadingValueSource<TValue> dengan nilai awal Unit
888 unit.
builder.Services.AddNotifyingCascadingValue(new NotifyingDalek() { Units = 888 });
Catatan
Untuk solusi berupa proyek server dan klien (Blazor Web App), kode yang telah disebutkan sebelumnya ditempatkan dalam file setiap proyek .Client
.
Komponen berikut digunakan untuk menunjukkan bagaimana perubahan nilai NotifyingDalek.Units
memberi tahu pelanggan yang berlangganan.
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();
}
}
}
Untuk mendemonstrasikan beberapa pemberitahuan pelanggan, komponen DaleksMain
di bawah ini merender tiga komponen Daleks
. Ketika jumlah unit (Units
) dari satu komponen Dalek
diperbarui, dua komponen Dalek
penyedia layanan lainnya diperbarui.
DaleksMain.razor
:
@page "/daleks-main"
<PageTitle>Daleks Main</PageTitle>
<h1>Daleks Main</h1>
<Daleks />
<Daleks />
<Daleks />
Tambahkan tautan navigasi ke DaleksMain
komponen di 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>
Karena jenis CascadingValueSource<TValue> dalam contoh ini (NotifyingDalek
) adalah jenis kelas, Anda dapat memenuhi hampir semua persyaratan spesifikasi fitur pengelolaan status. Namun, langganan membuat overhead dan mengurangi performa, jadi tolok ukur performa pendekatan ini di aplikasi Anda dan bandingkan dengan pendekatan manajemen status lainnya sebelum mengadopsinya di aplikasi produksi dengan sumber daya pemrosesan dan memori yang dibatasi.
Setiap perubahan status (setiap perubahan nilai properti kelas) menyebabkan semua komponen yang berlangganan dirender ulang, tanpa memandang bagian mana dari status yang mereka gunakan. Hindari membuat satu kelas besar yang mewakili seluruh status aplikasi global. Sebagai gantinya, buat kelas yang lebih rinci dan urutkan secara terpisah dengan langganan khusus ke parameter berantai, memastikan bahwa hanya komponen yang berlangganan ke bagian tertentu dari status aplikasi yang terpengaruh oleh perubahan.
CascadingValue
komponen
Komponen leluhur menyediakan nilai berskala menggunakan Blazor komponen kerangka kerja CascadingValue
, yang membungkus subtree hierarki komponen dan memasok nilai tunggal ke semua komponen dalam subtreenya.
Contoh berikut menunjukkan alur informasi tema ke hierarki komponen untuk menyediakan kelas gaya CSS ke tombol dalam komponen turunan.
Kelas C# berikut ThemeInfo
menentukan informasi tema.
Catatan
Untuk contoh di bagian ini, namespace aplikasi adalah BlazorSample
. Saat bereksperimen dengan kode di aplikasi sampel Anda sendiri, ubah namespace aplikasi ke namespace aplikasi sampel Anda.
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; }
}
}
Komponen tata letak berikut menentukan informasi tema (ThemeInfo
) sebagai nilai bertingkat untuk semua komponen yang membentuk isi Body tata letak properti.
ButtonClass
diberi nilai btn-success
, yang merupakan gaya tombol Bootstrap. Setiap komponen turunan dalam hierarki komponen dapat menggunakan ButtonClass
properti melalui nilai berskala 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" };
}
Blazor Web Apps menyediakan pendekatan alternatif untuk nilai bertingkat yang berlaku lebih luas ke aplikasi daripada melengkungkannya melalui satu file tata letak:
Bungkus markup
Routes
komponen dalamCascadingValue
komponen untuk menentukan data sebagai nilai berskala untuk semua komponen aplikasi.Contoh data kaskade
ThemeInfo
berikut dariRoutes
komponen.Routes.razor
:<CascadingValue Value="theme"> <Router ...> ... </Router> </CascadingValue> @code { private ThemeInfo theme = new() { ButtonClass = "btn-success" }; }
Catatan
Membungkus
Routes
instans komponen dalamApp
komponen (Components/App.razor
) denganCascadingValue
komponen tidak didukung.Tentukan nilai berskala tingkat akar sebagai layanan dengan memanggil AddCascadingValue metode ekstensi pada penyusun kumpulan layanan.
Contoh data kaskade
ThemeInfo
berikut dariProgram
file.Program.cs
builder.Services.AddCascadingValue(sp => new ThemeInfo() { ButtonClass = "btn-primary" });
Untuk informasi selengkapnya, lihat bagian berikut dari artikel ini:
atribut [CascadingParameter]
Untuk menggunakan nilai kaskade, komponen descendent mendeklarasikan parameter kaskade menggunakan [CascadingParameter]
atribut . Nilai berskala terikat ke parameter berskala berdasarkan jenis. Kaskade beberapa nilai dengan jenis yang sama tercakup di bagian Beberapa nilai Berjendela nanti di artikel ini.
Komponen berikut mengikat ThemeInfo
nilai berskala ke parameter kaskading, secara opsional menggunakan nama yang sama dari ThemeInfo
. Parameter digunakan untuk mengatur kelas CSS untuk tombol 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]
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++;
}
}
Mirip dengan parameter komponen reguler, komponen yang menerima parameter kaskading dirender saat nilai kaskading diubah. Misalnya, mengonfigurasi instans ThemedCounter
tema yang berbeda menyebabkan komponen dari bagian CascadingValue
komponen dirender ulang.
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 dapat digunakan untuk menunjukkan bahwa parameter berskala tidak berubah setelah inisialisasi.
Nilai/parameter berskala dan batas mode render
Parameter berskala tidak meneruskan data di seluruh batas mode render:
Sesi interaktif berjalan dalam konteks yang berbeda dari halaman yang menggunakan penyajian sisi server statis (SSR statis). Tidak ada persyaratan bahwa server yang memproduksi halaman bahkan merupakan komputer yang sama yang menghosting beberapa sesi Server Interaktif nanti, termasuk untuk komponen WebAssembly di mana server adalah komputer yang berbeda dengan klien. Manfaat penyajian sisi server statis (SSR statis) adalah untuk mendapatkan performa penuh penyajian HTML stateless murni.
Status yang melintasi batas antara penyajian statis dan interaktif harus dapat diserialisasikan. Komponen adalah objek arbitrer yang mereferensikan rantai besar objek lain, termasuk perender, kontainer DI, dan setiap instans layanan DI. Anda harus secara eksplisit menyebabkan status diserialisasikan dari SSR statis agar tersedia dalam komponen yang dirender secara interaktif berikutnya. Dua pendekatan diadopsi:
- Blazor Melalui kerangka kerja, parameter yang diteruskan di seluruh SSR statis ke batas penyajian interaktif diserialisasikan secara otomatis jika dapat diserialisasikan JSON, atau kesalahan dilemparkan.
- Status yang disimpan dalam diserialisasikan dan dipulihkan
PersistentComponentState
secara otomatis jika dapat diserialisasikan JSON, atau kesalahan dilemparkan.
Parameter berjenjang tidak dapat diserialisasikan JSON karena pola penggunaan umum untuk parameter berjenjang agak seperti layanan DI. Seringkali ada varian parameter kaskading khusus platform, sehingga tidak akan membantu pengembang jika kerangka kerja menghentikan pengembang agar tidak memiliki versi khusus interaktif server atau versi khusus WebAssembly. Selain itu, banyak nilai parameter berjenjang secara umum tidak dapat diserialisasikan, sehingga tidak praktis untuk memperbarui aplikasi yang ada jika Anda harus berhenti menggunakan semua nilai parameter berjenjang yang tidak dapat diserialisasi.
Rekomendasi:
Jika Anda perlu membuat status tersedia untuk semua komponen interaktif sebagai parameter kaskading, sebaiknya gunakan nilai berskala tingkat akar atau nilai berskala tingkat akar dengan pemberitahuan. Pola pabrik tersedia, dan aplikasi dapat memancarkan nilai yang diperbarui setelah pengaktifan aplikasi. Nilai kaskading tingkat akar tersedia untuk semua komponen, termasuk komponen interaktif, karena diproses sebagai layanan DI.
Untuk penulis pustaka komponen, Anda dapat membuat metode ekstensi untuk konsumen pustaka yang mirip dengan yang berikut ini:
builder.Services.AddLibraryCascadingParameters();
Instruksikan pengembang untuk memanggil metode ekstensi Anda. Ini adalah alternatif yang baik untuk menginstruksikan mereka untuk menambahkan
<RootComponent>
komponen dalam komponennyaMainLayout
.
Kaskade beberapa nilai
Untuk menyimpan beberapa nilai dengan jenis yang sama dalam subtree yang sama, berikan string unik Name untuk setiap CascadingValue
komponen dan atribut[CascadingParameter]
sesuai.
Dalam contoh berikut, dua CascadingValue
komponen kaskade instans yang berbeda dari CascadingType
:
<CascadingValue Value="parentCascadeParameter1" Name="CascadeParam1">
<CascadingValue Value="ParentCascadeParameter2" Name="CascadeParam2">
...
</CascadingValue>
</CascadingValue>
@code {
private CascadingType? parentCascadeParameter1;
[Parameter]
public CascadingType? ParentCascadeParameter2 { get; set; }
}
Dalam komponen turunan, parameter berkaskade menerima nilai kaskadenya dari komponen leluhur dengan Name:
@code {
[CascadingParameter(Name = "CascadeParam1")]
protected CascadingType? ChildCascadeParameter1 { get; set; }
[CascadingParameter(Name = "CascadeParam2")]
protected CascadingType? ChildCascadeParameter2 { get; set; }
}
Meneruskan data di seluruh hierarki komponen
Parameter berskala juga memungkinkan komponen untuk meneruskan data di seluruh hierarki komponen. Pertimbangkan contoh set tab UI berikut, di mana komponen kumpulan tab mempertahankan serangkaian tab individual.
Catatan
Untuk contoh di bagian ini, namespace aplikasi adalah BlazorSample
. Saat bereksperimen dengan kode di aplikasi sampel Anda sendiri, ubah namespace ke namespace aplikasi sampel Anda.
Buat ITab
antarmuka yang diterapkan tab dalam folder bernama UIInterfaces
.
UIInterfaces/ITab.cs
:
using Microsoft.AspNetCore.Components;
namespace BlazorSample.UIInterfaces;
public interface ITab
{
RenderFragment ChildContent { get; }
}
Catatan
Untuk informasi selengkapnya tentang RenderFragment, lihat Razor ASP.NET Core.
Komponen berikut TabSet
mempertahankan sekumpulan tab. Komponen kumpulan Tab
tab, yang dibuat nanti di bagian ini, berikan item daftar (<li>...</li>
) untuk daftar (<ul>...</ul>
).
Komponen anak Tab
tidak secara eksplisit diteruskan sebagai parameter ke TabSet
. Sebaliknya, komponen anak Tab
adalah bagian dari konten anak dari TabSet
. Namun, TabSet
masih memerlukan referensi ke setiap Tab
komponen sehingga dapat merender header dan tab aktif. Untuk mengaktifkan koordinasi ini tanpa memerlukan kode tambahan, TabSet
komponen dapat menyediakan dirinya sebagai nilai bertingkat yang kemudian diambil oleh komponen keturunan 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();
}
}
}
Tab
Komponen turunan menangkap yang berisi TabSet
sebagai parameter berskala. Komponen Tab
menambahkan diri mereka ke TabSet
dan berkoordinasi untuk mengatur tab aktif.
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);
}
}
Komponen berikut ExampleTabSet
menggunakan TabSet
komponen , yang berisi tiga Tab
komponen.
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;
}
Sumber Daya Tambahan:
ASP.NET Core