Události
Mistrovství Světa v Power BI DataViz
14. 2. 16 - 31. 3. 16
Se 4 šance na vstup, můžete vyhrát konferenční balíček a udělat to na LIVE Grand Finale v Las Vegas
Další informaceTento prohlížeč se už nepodporuje.
Upgradujte na Microsoft Edge, abyste mohli využívat nejnovější funkce, aktualizace zabezpečení a technickou podporu.
Poznámka
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozornění
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.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Tento článek vysvětluje, jak pomocí atributu @key
direktiv zachovat relace elementu, komponenty a modelu při vykreslování a následné změně prvků nebo komponent.
Při vykreslování seznamu prvků nebo součástí a prvků nebo součástí se následně musí rozhodnout, Blazor které z předchozích prvků nebo součástí jsou zachovány a jak se mají objekty modelu mapovat na ně. Obvykle je tento proces automatický a dostatečný pro obecné vykreslování, ale často existují případy, kdy řízení procesu pomocí atributu @key
direktivy vyžaduje.
Podívejte se na následující příklad, který ukazuje problém mapování kolekce, který je vyřešen pomocí @key
.
Pro následující komponenty:
Details
přijímá data (Data
) z nadřazené komponenty, která se zobrazí v elementu <input>
. Jednotlivé zobrazené elementy <input>
můžou získat fokus stránky, když uživatel vybere některý z elementů <input>
.Details
komponenty. Každé tři sekundy se do kolekce přidá nová osoba.Tato ukázka umožňuje:
<input>
z několika vykreslených komponent Details
.Details.razor
:
<input value="@Data" />
@code {
[Parameter]
public string? Data { get; set; }
}
<input value="@Data" />
@code {
[Parameter]
public string? Data { get; set; }
}
<input value="@Data" />
@code {
[Parameter]
public string? Data { get; set; }
}
<input value="@Data" />
@code {
[Parameter]
public string? Data { get; set; }
}
<input value="@Data" />
@code {
[Parameter]
public string Data { get; set; }
}
<input value="@Data" />
@code {
[Parameter]
public string Data { get; set; }
}
Každá iterace přidání osoby v OnTimerCallback
následující nadřazené komponentě vede k Blazor opětovnému sestavení celé kolekce. Fokus stránky zůstane v elementech <input>
na pozici se stejným indexem, takže se při každém přidání uživatele posune. Posun fokusu mimo uživatelem vybraný element není žádoucí. Po ukázce špatného chování na následující komponentě se k vylepšení uživatelského prostředí používá atribut direktivy @key
.
People.razor
:
@page "/people"
@using System.Timers
@implements IDisposable
<PageTitle>People</PageTitle>
<h1>People Example</h1>
@foreach (var person in people)
{
<Details Data="@person.Data" />
}
@code {
private Timer timer = new Timer(3000);
public List<Person> people =
new()
{
{ new Person { Data = "Person 1" } },
{ new Person { Data = "Person 2" } },
{ new Person { Data = "Person 3" } }
};
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
people.Insert(0,
new Person
{
Data = $"INSERTED {DateTime.Now.ToString("hh:mm:ss tt")}"
});
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
public class Person
{
public string? Data { get; set; }
}
}
People.razor
:
@page "/people"
@using System.Timers
@implements IDisposable
<PageTitle>People</PageTitle>
<h1>People Example</h1>
@foreach (var person in people)
{
<Details Data="@person.Data" />
}
@code {
private Timer timer = new Timer(3000);
public List<Person> people =
new()
{
{ new Person { Data = "Person 1" } },
{ new Person { Data = "Person 2" } },
{ new Person { Data = "Person 3" } }
};
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
people.Insert(0,
new Person
{
Data = $"INSERTED {DateTime.Now.ToString("hh:mm:ss tt")}"
});
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
public class Person
{
public string? Data { get; set; }
}
}
PeopleExample.razor
:
@page "/people-example"
@using System.Timers
@implements IDisposable
@foreach (var person in people)
{
<Details Data="person.Data" />
}
@code {
private Timer timer = new Timer(3000);
public List<Person> people =
new()
{
{ new Person { Data = "Person 1" } },
{ new Person { Data = "Person 2" } },
{ new Person { Data = "Person 3" } }
};
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
people.Insert(0,
new Person
{
Data = $"INSERTED {DateTime.Now.ToString("hh:mm:ss tt")}"
});
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
public class Person
{
public string? Data { get; set; }
}
}
PeopleExample.razor
:
@page "/people-example"
@using System.Timers
@implements IDisposable
@foreach (var person in people)
{
<Details Data="person.Data" />
}
@code {
private Timer timer = new Timer(3000);
public List<Person> people =
new()
{
{ new Person { Data = "Person 1" } },
{ new Person { Data = "Person 2" } },
{ new Person { Data = "Person 3" } }
};
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
people.Insert(0,
new Person
{
Data = $"INSERTED {DateTime.Now.ToString("hh:mm:ss tt")}"
});
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
public class Person
{
public string? Data { get; set; }
}
}
PeopleExample.razor
:
@page "/people-example"
@using System.Timers
@implements IDisposable
@foreach (var person in people)
{
<Details Data="person.Data" />
}
@code {
private Timer timer = new Timer(3000);
public List<Person> people =
new()
{
{ new Person { Data = "Person 1" } },
{ new Person { Data = "Person 2" } },
{ new Person { Data = "Person 3" } }
};
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
people.Insert(0,
new Person
{
Data = $"INSERTED {DateTime.Now.ToString("hh:mm:ss tt")}"
});
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
public class Person
{
public string Data { get; set; }
}
}
PeopleExample.razor
:
@page "/people-example"
@using System.Timers
@implements IDisposable
@foreach (var person in people)
{
<Details Data="person.Data" />
}
@code {
private Timer timer = new Timer(3000);
public List<Person> people =
new List<Person>()
{
{ new Person { Data = "Person 1" } },
{ new Person { Data = "Person 2" } },
{ new Person { Data = "Person 3" } }
};
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
people.Insert(0,
new Person
{
Data = $"INSERTED {DateTime.Now.ToString("hh:mm:ss tt")}"
});
StateHasChanged();
});
}
public void Dispose() => timer.Dispose();
public class Person
{
public string Data { get; set; }
}
}
Obsah kolekce people
se změní při vložení, odstranění nebo změně pořadí položek. Opětovné vykreslování může mít za následek viditelné změny chování. Například při každém vložení osoby do people
kolekce dojde ke ztrátě fokusu uživatele.
Proces mapování elementů nebo komponent na kolekci je možné řídit pomocí atributu direktivy @key
. Použitím atributu @key
se zajistí zachování elementů nebo komponent na základě hodnoty klíče. Pokud komponenta Details
ve výše uvedeném příkladu jako klíč používá položku person
, Blazor ignoruje vykreslování komponent Details
, které se nezměnily.
Chcete-li upravit nadřazenou komponentu @key
tak, aby používala atribut direktivy people
s kolekcí, aktualizujte <Details>
prvek na následující:
<Details @key="person" Data="@person.Data" />
Při změně kolekce people
se zachová přidružení mezi instancemi Details
a instancemi person
. Když se na začátek kolekce vloží objekt Person
, na odpovídající pozici se vloží jedna nová instance Details
. Ostatní instance zůstanou beze změny. Proto se při přidávání osob do kolekce neztratí fokus uživatele.
Stejné chování při použití atributu direktivy @key
vykazují i ostatní aktualizace kolekcí:
Důležité
Klíče jsou lokální pro každý element nebo každou komponentu kontejneru. Klíče se neporovnávají globálně napříč dokumentem.
Obvykle dává smysl použít atribut @key
vždy, když se vykresluje seznam (například v bloku foreach
) a pro definování atributu @key
existuje vhodná hodnota.
Atribut @key
můžete použít také k zachování podstromu elementů nebo komponent, když nedojde ke změně objektu, jak ukazují následující příklady.
Příklad 1:
<li @key="person">
<input value="@person.Data" />
</li>
Příklad 2:
<div @key="person">
@* other HTML elements *@
</div>
Pokud dojde ke změně instance person
, atribut direktivy @key
přinutí Blazor, aby provedl následující:
<li>
nebo <div>
a jejich potomky.To je užitečné k zajištění, aby se při změně kolekce v rámci podstromu nezachoval žádný stav uživatelského rozhraní.
Atribut direktivy @key
má obor vymezený na podřízené elementy nadřazeného elementu na stejné úrovni.
Představte si následující příklad. Klíče first
a second
se porovnávají mezi sebou ve stejném oboru vnějšího elementu <div>
:
<div>
<div @key="first">...</div>
<div @key="second">...</div>
</div>
Následující příklad ukazuje klíče first
a second
ve vlastních oborech, které spolu nesouvisí a vzájemně se neovlivňují. Obor každého atributu @key
se vztahuje na vlastní nadřazený element <div>
, nikoli na ostatní nadřazené elementy <div>
:
<div>
<div @key="first">...</div>
</div>
<div>
<div @key="second">...</div>
</div>
V případě výše uvedené komponenty Details
následující příklady vykreslí data person
ve stejném oboru @key
a ukazují obvyklé případy použití atributu @key
:
<div>
@foreach (var person in people)
{
<Details @key="person" Data="@person.Data" />
}
</div>
@foreach (var person in people)
{
<div @key="person">
<Details Data="@person.Data" />
</div>
}
<ol>
@foreach (var person in people)
{
<li @key="person">
<Details Data="@person.Data" />
</li>
}
</ol>
V následujících příkladech je obor atributu @key
vymezený pouze na element <div>
nebo <li>
kolem každé instance komponenty Details
. Proto se pro data person
každého člena kolekce people
nepoužívá jako klíč každá instance person
napříč vykreslenými komponentami Details
. Při používání atributu @key
se vyhněte následujícím vzorům:
@foreach (var person in people)
{
<div>
<Details @key="person" Data="@person.Data" />
</div>
}
<ol>
@foreach (var person in people)
{
<li>
<Details @key="person" Data="@person.Data" />
</li>
}
</ol>
Vykreslování s použitím atributu @key
má dopad na výkon. Dopad na výkon není velký, ale přesto používejte atribut @key
pouze v případě, že je zachování prvku nebo komponenty pro aplikaci přínosné.
I když nepoužijete atribut @key
, Blazor zachovává instance podřízených elementů a komponent v co největší míře. Jedinou výhodou použití atributu @key
je to, že máte kontrolu nad tím, jak se instance modelu mapují na zachované instance komponent, namísto toho, aby mapování vybírala architektura Blazor.
Obecně je vhodné pro atribut @key
zadat některou z následujících hodnot:
Person
(person
). Tím se zajistí zachování na základě rovnosti odkazů na objekty.int
, string
nebo Guid
.Ujistěte se, že hodnoty použité pro atribut @key
nejsou v konfliktu. Pokud se v rámci stejného nadřazeného elementu zjistí kolidující hodnoty, Blazor vyvolá výjimku, protože nedokáže deterministicky mapovat staré elementy nebo komponenty na nové elementy nebo komponenty. Používejte pouze jedinečné hodnoty, například instance objektů nebo hodnoty primárního klíče.
Zpětná vazba k produktu ASP.NET Core
ASP.NET Core je open source projekt. Vyberte odkaz pro poskytnutí zpětné vazby:
Události
Mistrovství Světa v Power BI DataViz
14. 2. 16 - 31. 3. 16
Se 4 šance na vstup, můžete vyhrát konferenční balíček a udělat to na LIVE Grand Finale v Las Vegas
Další informaceŠkolení
Modul
Interakce s daty ve webových aplikacích Blazor - Training
Zjistěte, jak vytvořit grafické uživatelské rozhraní ve webové aplikaci Blazor vytvořením a sestavením komponent Blazor. Získejte přístup k datům a sdílejte je pro zobrazení na více stránkách v aplikaci.
Dokumentace
ASP.NET splatting atributu Core Blazor a libovolné parametry
Zjistěte, jak mohou komponenty kromě deklarovaných parametrů komponenty zachytit a vykreslit další atributy.
kontext synchronizace ASP.NET Core Blazor
Přečtěte si o Blazorkontextu synchronizace, o tom, jak se vyhnout volání blokující vlákna a jak vyvolat metody komponent externě.
Vyhněte se přepisování parametrů v ASP.NET Core Blazor
Přečtěte si, jak se vyhnout přepisování parametrů v Blazor aplikacích během opětovnéhoenderování.