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.
Varování
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Pro aktuální vydání si přečtěte článek ve verzi .NET 9.
Tento článek vysvětluje Razor vykreslování komponent v aplikacích ASP.NET Core Blazor, včetně toho, kdy volat StateHasChanged k ručnímu spuštění vykreslování komponenty.
Konvence vykreslování pro ComponentBase
Komponenty se musí vykreslit, když jsou poprvé přidány do hierarchie komponent nadřazenou komponentou. Jediný okamžik, kdy musí být komponenta vykreslena. Komponenty se můžou vykreslovat v jiných okamžicích podle vlastní logiky a konvencí.
Razor komponenty dědí ze ComponentBase základní třídy, která obsahuje logiku pro aktivaci rerenderingu v následujících časech:
- Po použití aktualizované sady parametrů z nadřazené komponenty.
- Po použití aktualizované hodnoty pro kaskádový parametr.
- Po oznámení události a vyvolání jednoho z vlastních obslužných rutin události.
- Po volání své vlastní metody
(viz životní cyklus komponent ASP.NET Core ). Pokyny k tomu, jak zabránit přepsání parametrů podřízené komponenty, pokud StateHasChanged je volána v nadřazené komponentě, naleznete v tématu Vyhněte se přepsání parametrů v ASP.NET Core Blazor.
Komponenty zděděné z ComponentBase přeskočí opakované vykreslení kvůli aktualizacím parametrů, pokud platí některá z následujících podmínek:
Všechny parametry pocházejí ze sady známých typů† nebo jakéhokoli primitivního typu , který se od předchozí sady parametrů nezměnil.
† Framework Blazor používá sadu předdefinovaných pravidel a explicitní kontroly typů parametrů pro detekci změn. Tato pravidla a typy se můžou kdykoli změnit. Další informace najdete
ChangeDetectionv rozhraní API v referenčním zdroji ASP.NET Core.Poznámka:
Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí mezi větvemi nebo značkami. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Přepsání metody komponenty
vrací (výchozí implementace vždy vrací ).
Řízení toku vykreslování
Ve většině případů ComponentBase konvence vedou ke správné podmnožině opětovného vykreslení komponent po události. Vývojáři obvykle nemusí poskytovat ruční logiku, která určuje frameworku, které komponenty se mají znovu vykreslit a kdy je znovu vykreslit. Celkový účinek konvencí rámce spočívá v tom, že komponenta, která přijímá událost, se přerenderuje, což rekurzivně spouští přerenderování následnických komponent, jejichž hodnoty parametrů se mohly změnit.
Další informace o dopadech na výkon konvencí architektury a o tom, jak optimalizovat hierarchii komponent aplikace pro vykreslování, najdete v osvědčených postupech pro vykreslování ASP.NET CoreBlazor.
Streamované vykreslování
Použijte streamované vykreslování se statickým vykreslováním na straně serveru (static SSR) nebo předvykreslením pro streamování aktualizací obsahu v toku odpovědí a zlepšení uživatelského zážitku u komponent, které vykonávají dlouhotrvající asynchronní úlohy, které potřebují plně vykreslit.
Představte si například komponentu, která provádí dlouhotrvající databázový dotaz nebo volání webového rozhraní API k vykreslení dat při načítání stránky. Asynchronní úlohy prováděné v rámci vykreslování součásti na straně serveru se obvykle musí dokončit před odesláním vykreslené odpovědi, která může zpozdit načtení stránky. Jakékoli významné zpoždění při vykreslování stránky poškodí uživatelské prostředí. Pro zlepšení uživatelského prostředí streamovací vykreslování nejprve rychle vykreslí celou stránku se zástupným obsahem, během provádění asynchronních operací. Po dokončení operací se aktualizovaný obsah odešle klientovi na stejném připojení pro odpověď a vloží se do modelu DOM.
Streamové vykreslování vyžaduje, aby server zabránil ukládání výstupu do vyrovnávací paměti. Data odpovědi musí ke klientovi plynout, jakmile jsou generována. U hostitelů, kteří vynucují ukládání do vyrovnávací paměti, plynule klesá kvalita streamovaného vykreslování, a stránka se načítá bez streamovaného vykreslování.
Chcete-li streamovat aktualizace obsahu při použití statického vykreslování na straně serveru (statické SSR) nebo předběžného vykreslování, použijte pro komponentu atribut [StreamRendering] v rozhraní .NET 9 nebo novější (použijte [StreamRendering(true)] v .NET 8). Streamované vykreslování musí být výslovně povoleno, protože streamované aktualizace můžou způsobit posun obsahu na stránce. Komponenty bez atributu automaticky přijímají streamovací vykreslování, pokud rodičovská komponenta tuto funkci používá. Odevzdáním false atributu podřízené komponentě zakážete funkci v tomto okamžiku a dále v podstromu komponenty. Atribut je funkční při použití na součásti dodané knihovnou Razortříd.
Pokud je vylepšená navigace aktivní, streamované vykreslování zobrazuje odpovědi Nenalezeno bez opětovného načtení stránky. Pokud je vylepšená navigace blokovaná, rámec přesměruje na stránku s obsahem "Stránka nenalezena" s aktualizací stránky.
Streamované vykreslování může vykreslovat pouze komponenty, které mají trasu, jako například NotFoundPage přiřazení (NotFoundPage="...") nebo přiřazení stránky pro middleware znovu provádějící stránky se stavovým kódem (UseStatusCodePagesWithReExecute). Fragment vykreslení nenalezen (<NotFound>...</NotFound>) a obsah 404 DefaultNotFound ("Not found" jako prostý text) nemají trasy, takže je nelze použít během streamovaného vykreslování.
Vykreslování obsahu streamování NavigationManager.NotFound používá (v pořadí):
- Předaný
NotFoundPagekomponentěRouter, pokud je přítomna. - Stránka Se stavovým kódem znovu spustí middlewarovou stránku( pokud je nakonfigurovaná).
- Pokud není přijat žádný z předchozích přístupů, žádná akce.
Vykreslování nestreamovaného NavigationManager.NotFound obsahu používá (v pořadí):
- Předaný
NotFoundPagekomponentěRouter, pokud je přítomna. - Nenalezen obsah fragmentu vykreslování, pokud je přítomen. Nedoporučuje se v .NET 10 nebo novějším.
-
DefaultNotFoundObsah 404 ("Not foundprostý text").
Middleware pro opětovné spuštění stavových kódů má přednost při řešení problémů se směrováním adres URL v prohlížeči, jako je například nesprávná adresa URL zadaná do adresního řádku prohlížeče nebo výběr odkazu, který nemá v aplikaci žádný koncový bod.
Následující příklad je založený na Weather komponentě v aplikaci vytvořené ze Blazor Web App šablony projektu. Volání na Task.Delay simuluje asynchronní získávání dat o počasí. Komponenta zpočátku vykresluje zástupný obsah ("Loading...") bez čekání, až asynchronní zpoždění uplyne. Když je dokončeno asynchronní zpoždění a jsou vygenerována data o počasí, obsah je streamován do odpovědi a vloží se do tabulky předpovědi počasí.
Weather.razor:
@page "/weather"
@attribute [StreamRendering]
...
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
...
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
...
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
await Task.Delay(500);
...
forecasts = ...
}
}
Potlačení aktualizace uživatelského rozhraní (ShouldRender)
ShouldRender se volá při každém vykreslení komponenty. Přepište ShouldRender, abyste spravovali aktualizaci uživatelského rozhraní. Pokud se implementace vrátí true, uživatelské rozhraní se aktualizuje.
I když se ShouldRender přepíše, komponenta se vždy nejprve vykreslí.
ControlRender.razor:
@page "/control-render"
<PageTitle>Control Render</PageTitle>
<h1>Control Render Example</h1>
<label>
<input type="checkbox" @bind="shouldRender" />
Should Render?
</label>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private bool shouldRender = true;
protected override bool ShouldRender() => shouldRender;
private void IncrementCount() => currentCount++;
}
@page "/control-render"
<PageTitle>Control Render</PageTitle>
<h1>Control Render Example</h1>
<label>
<input type="checkbox" @bind="shouldRender" />
Should Render?
</label>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private bool shouldRender = true;
protected override bool ShouldRender() => shouldRender;
private void IncrementCount() => currentCount++;
}
@page "/control-render"
<label>
<input type="checkbox" @bind="shouldRender" />
Should Render?
</label>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private bool shouldRender = true;
protected override bool ShouldRender()
{
return shouldRender;
}
private void IncrementCount()
{
currentCount++;
}
}
@page "/control-render"
<label>
<input type="checkbox" @bind="shouldRender" />
Should Render?
</label>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private bool shouldRender = true;
protected override bool ShouldRender()
{
return shouldRender;
}
private void IncrementCount()
{
currentCount++;
}
}
@page "/control-render"
<label>
<input type="checkbox" @bind="shouldRender" />
Should Render?
</label>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private bool shouldRender = true;
protected override bool ShouldRender()
{
return shouldRender;
}
private void IncrementCount()
{
currentCount++;
}
}
@page "/control-render"
<label>
<input type="checkbox" @bind="shouldRender" />
Should Render?
</label>
<p>Current count: @currentCount</p>
<p>
<button @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private bool shouldRender = true;
protected override bool ShouldRender()
{
return shouldRender;
}
private void IncrementCount()
{
currentCount++;
}
}
Další informace o osvědčených postupech z hlediska výkonu týkající se ShouldRender najdete v části Osvědčené postupy pro vykreslování výkonu ASP.NET CoreBlazor.
StateHasChanged
Volání StateHasChanged zařadí přerozebrání k provedení, když je hlavní vlákno aplikace volné.
Komponenty jsou vyřazeny do fronty pro vykreslování a nejsou znovu vyřazeny, pokud již existuje čekající rerender. Pokud komponenta volá StateHasChanged pětkrát za sebou ve smyčce, komponenta se vykreslí jen jednou. Toto chování je zakódováno v ComponentBase, který nejprve zkontroluje, zda je rerender již zařazen do fronty, než zařadí další.
Komponenta se může během stejného cyklu vykreslit vícekrát, což se běžně vyskytuje, když má komponenta podřízené položky, které vzájemně spolupracují:
- Nadřazená komponenta vykreslí několik podřízených komponent.
- Podřízené komponenty vykreslují a aktivují aktualizaci nadřazeného objektu.
- Nadřazená komponenta přerenderuje s novým stavem.
Tento návrh umožňuje volat StateHasChanged v případě potřeby, aniž by hrozilo zavedení zbytečného vykreslování. Chování jednotlivých komponent můžete vždy převzít pod kontrolu přímou implementací IComponent a ručním ovládáním okamžiku, kdy se komponenta vykreslí.
Vezměte v úvahu následující IncrementCount metodu, která zvyšuje počet, volá StateHasChanged, a znovu zvyšuje počet:
private void IncrementCount()
{
currentCount++;
StateHasChanged();
currentCount++;
}
Při krokování kódu v ladicím programu si můžete myslet, že počet se v uživatelském rozhraní aktualizuje při prvním currentCount++ spuštění ihned po zavolání StateHasChanged. Uživatelské rozhraní ale v tomto okamžiku nezobrazuje aktualizovaný počet kvůli synchronnímu zpracování, které probíhá při provádění této metody. Není možné, aby renderer vykreslil komponentu, dokud se obslužná rutina události nedokončí. Uživatelské rozhraní zobrazuje nárůst pro obě vykonávání během jediného vykreslení.
Pokud očekáváte něco uvnitř currentCount++ řádků, dává očekávané volání rendereru příležitost k vykreslení. To vedlo k tomu, že někteří vývojáři využívali funkci Delay s jedním milisekundovým zpožděním ve svých komponentách, aby se vykreslení mohlo uskutečnit, ale nedoporučujeme bez rozmyslu zpomalovat aplikaci, aby se mohlo vykreslit.
Nejlepší přístup je použít "await Task.Yield", což vynutí, aby komponent zpracoval kód asynchronně a vykreslil během aktuální skupiny, s druhým vykreslením v samostatné skupině po dokončení úlohy a pokračování.
Vezměte v úvahu následující revidovanou IncrementCount metodu, která aktualizuje uživatelské rozhraní dvakrát, protože vykreslení StateHasChanged ve frontě je provedeno při provedení úlohy s voláním Task.Yield:
private async Task IncrementCount()
{
currentCount++;
StateHasChanged();
await Task.Yield();
currentCount++;
}
Dávejte pozor, abyste nevhodně nezavolali StateHasChanged, což je běžná chyba, která zvyšuje zbytečné nároky na vykreslování. Kód by neměl volat StateHasChanged, když:
- Rutinní zpracování událostí, ať už synchronně nebo asynchronně, neboť ComponentBase vyvolává vykreslení pro většinu obvyklých obslužných rutin událostí.
- Implementace typické logiky životního cyklu, například
OnInitializedneboOnParametersSetAsync, ať už synchronně nebo asynchronně, protože ComponentBase aktivuje vykreslení pro typické události životního cyklu.
Může ale dávat smysl volat StateHasChanged v případech popsaných v následujících částech tohoto článku:
- Asynchronní obslužná rutina zahrnuje několik asynchronních fází.
- Příjem volání z externího zdroje do Blazor systému vykreslování a zpracování událostí
- Vykreslení komponenty mimo podstrom, jenž je konkrétní událostí znovu vykreslen
Asynchronní obslužná rutina zahrnuje několik asynchronních fází.
Vzhledem ke způsobu, jakým jsou úkoly definovány v .NET, může příjemce objektu Task sledovat pouze jeho konečné dokončení, nikoli přechodné asynchronní stavy.
ComponentBase Proto může spustit přerenderování pouze tehdy, když je Task poprvé vrácen a když je Task nakonec dokončen. Architektura nemůže zjistit, jak rerenderovat komponentu v jiných přechodných bodech, například když IAsyncEnumerable<T>vrátí data v řadě mezilehlých Taskbodů. Pokud chcete přerenderovat v přechodných bodech, v těchto bodech zavolejte StateHasChanged.
Vezměte v úvahu následující CounterState1 komponentu, která aktualizuje počet čtyřikrát při IncrementCount každém spuštění metody:
- Automatické vykreslení probíhá po prvním a posledním přírůstku
currentCount. - Ruční vykreslení se spouští voláním StateHasChanged, když framework automaticky nespustí opětovné vykreslování v přechodných bodech zpracování, při kterých se zvýší
currentCount.
CounterState1.razor:
@page "/counter-state-1"
<PageTitle>Counter State 1</PageTitle>
<h1>Counter State Example 1</h1>
<p>
Current count: @currentCount
</p>
<p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private async Task IncrementCount()
{
currentCount++;
// Renders here automatically
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
// Renders here automatically
}
}
@page "/counter-state-1"
<PageTitle>Counter State 1</PageTitle>
<h1>Counter State Example 1</h1>
<p>
Current count: @currentCount
</p>
<p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private async Task IncrementCount()
{
currentCount++;
// Renders here automatically
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
// Renders here automatically
}
}
@page "/counter-state-1"
<p>
Current count: @currentCount
</p>
<p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private async Task IncrementCount()
{
currentCount++;
// Renders here automatically
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
// Renders here automatically
}
}
@page "/counter-state-1"
<p>
Current count: @currentCount
</p>
<p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private async Task IncrementCount()
{
currentCount++;
// Renders here automatically
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
// Renders here automatically
}
}
@page "/counter-state-1"
<p>
Current count: @currentCount
</p>
<p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private async Task IncrementCount()
{
currentCount++;
// Renders here automatically
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
// Renders here automatically
}
}
@page "/counter-state-1"
<p>
Current count: @currentCount
</p>
<p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>
@code {
private int currentCount = 0;
private async Task IncrementCount()
{
currentCount++;
// Renders here automatically
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
StateHasChanged();
await Task.Delay(1000);
currentCount++;
// Renders here automatically
}
}
Příjem volání od něčeho externího k systému vykreslování a zpracování událostí
ComponentBase zná pouze své vlastní metody životního cyklu a události spuštěné Blazor. ComponentBase neví o jiných událostech, ke kterým může dojít v kódu. Například všechny události jazyka C# vyvolané vlastním úložištěm dat nejsou známy Blazor. Aby tyto události aktivovaly opětovné zobrazení aktualizovaných hodnot v uživatelském rozhraní, zavolejte StateHasChanged.
Zvažte následující CounterState2 komponentu, která používá System.Timers.Timer k aktualizaci počtu v pravidelných intervalech a voláních StateHasChanged pro aktualizaci uživatelského rozhraní:
-
OnTimerCallbackse spouští mimo jakýkoli tok vykreslování spravovaný Blazor nebo mimo oznámení události. Proto je nutné volatOnTimerCallback, StateHasChanged protože Blazor neví o změnáchcurrentCountve zpětném volání. - Komponenta implementuje IDisposable, přičemž Timer je uvolněna, když architektura zavolá metodu
Dispose. Další informace najdete v tématu odstranění komponenty ASP.NET Core Razor.
Vzhledem k tomu, že zpětné volání je vyvoláno mimo Blazorkontext synchronizace, musí komponenta zabalit logiku OnTimerCallbackComponentBase.InvokeAsync, aby se přesunula do kontextu synchronizace rendereru. To odpovídá přesměrování do vlákna uživatelského rozhraní v jiných frameworkech uživatelského rozhraní.
StateHasChanged lze volat pouze z kontextu synchronizace rendereru a v opačném případě vyvolá výjimku.
System.InvalidOperationException: Aktuální vlákno není přidruženo k Dispatcheru. Pomocí InvokeAsync() můžete předat řízení Dispečerovi při aktivaci vykreslování nebo změně stavu součásti.
CounterState2.razor:
@page "/counter-state-2"
@using System.Timers
@implements IDisposable
<PageTitle>Counter State 2</PageTitle>
<h1>Counter State Example 2</h1>
<p>
This counter demonstrates <code>Timer</code> disposal.
</p>
<p>
Current count: @currentCount
</p>
@code {
private int currentCount = 0;
private Timer timer = new(1000);
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
currentCount++;
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable
<PageTitle>Counter State 2</PageTitle>
<h1>Counter State Example 2</h1>
<p>
This counter demonstrates <code>Timer</code> disposal.
</p>
<p>
Current count: @currentCount
</p>
@code {
private int currentCount = 0;
private Timer timer = new(1000);
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
currentCount++;
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>
Current count: @currentCount
</p>
@code {
private int currentCount = 0;
private Timer timer = new(1000);
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
currentCount++;
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>
Current count: @currentCount
</p>
@code {
private int currentCount = 0;
private Timer timer = new(1000);
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
currentCount++;
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>
Current count: @currentCount
</p>
@code {
private int currentCount = 0;
private Timer timer = new(1000);
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
currentCount++;
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>
Current count: @currentCount
</p>
@code {
private int currentCount = 0;
private Timer timer = new Timer(1000);
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
currentCount++;
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
}
Vykreslení komponenty mimo podstrom, který je reenderován konkrétní událostí
Uživatelské rozhraní může zahrnovat:
- Poslání události jedné komponentě
- Změna stavu.
- Opětovné vykreslení zcela jiné komponenty, která není potomkem komponenty přijímající událost.
Jedním ze způsobů, jak tento scénář vyřešit, je poskytnout třídu správy stavu, často jako službu injektáže závislostí (DI), která se vloží do více komponent. Když jedna komponenta volá metodu ve správci stavů, správce stavů vyvolá událost jazyka C#, která je následně přijata nezávislou komponentou.
Přístupy ke správě stavu najdete v následujících zdrojích informací:
- Vytvořte vazbu mezi více než dvěma komponentami pomocí datových vazeb.
- Předávání dat v hierarchii komponent pomocí kaskádových hodnot a parametrů
- Část Služby kontejneru stavu v paměti v přehledu správy stavu
U přístupu správce stavů se události jazyka Blazor C# nacházejí mimo kanál vykreslování. Zavolejte StateHasChanged na další komponenty, které chcete znovu vykreslit v reakci na události správce stavů.
Přístup správce stavů se podobá dřívějšímu případu s System.Timers.Timer ve předchozí části. Vzhledem k tomu, že zásobník volání v rámci provádění obvykle zůstává v kontextu synchronizace rendereru, volání InvokeAsync se nevyžaduje. Volání InvokeAsync je vyžadováno pouze v případě, že logika unikne kontextu synchronizace, například volání ContinueWith na Task nebo čekání na Task s ConfigureAwait(false). Další informace najdete v části Příjem volání z něčeho externího vůči systému Blazor, který zpracovává vykreslování a události.
Indikátor průběhu načítání WebAssembly pro Blazor Web Apps
Aplikace může přijmout vlastní kód k vytvoření indikátoru průběhu načítání. Další informace najdete v tématu