Připojení kódu C# k událostem MODELU DOM pomocí obslužných rutin událostí Blazor
Většina elementů HTML zveřejňuje události, které se aktivují, když dojde k nějaké významné události, například po dokončení načítání stránky, uživatel kliknul na tlačítko nebo se změnil obsah elementu HTML. Aplikace dokáže zpracovat událost několika způsoby:
- Aplikace může událost ignorovat.
- Aplikace může ke zpracování události spustit obslužnou rutinu události napsanou v JavaScriptu.
- Aplikace může ke zpracování události spustit obslužnou rutinu události Blazor napsanou v jazyce C#.
V této lekci se podrobněji podíváte na třetí možnost; jak vytvořit obslužnou rutinu události Blazor v jazyce C# pro zpracování události.
Zpracování události pomocí Blazoru a C#
Každý prvek v kódu HTML aplikace Blazor podporuje mnoho událostí. Většina těchto událostí odpovídá událostem MODELU DOM dostupným v běžných webových aplikacích, ale můžete také vytvářet uživatelem definované události, které se aktivují napsáním kódu. Pokud chcete zachytit událost pomocí Blazoru, napíšete metodu jazyka C#, která zpracovává událost, a pak svážete událost s metodou pomocí direktivy Blazor. V případě události MODELU DOM sdílí direktiva Blazor stejný název jako ekvivalentní událost HTML, například @onkeydown
nebo @onfocus
. Ukázková aplikace vygenerovaná pomocí aplikace Blazor Server Například obsahuje následující kód na stránce Counter.razor . Na této stránce se zobrazí tlačítko. Když uživatel tlačítko vybere, @onclick
událost aktivuje IncrementCount
metodu, která zvýší čítač označující, kolikrát bylo tlačítko kliknuto. Hodnota proměnné čítače je zobrazena elementem <p> na stránce:
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
Mnoho metod obslužné rutiny události vezme parametr, který poskytuje další kontextové informace. Tento parametr se označuje jako EventArgs
parametr. Například událost předává informace o tom, @onclick
na které tlačítko uživatel klikl, nebo jestli současně stiskl tlačítko, například Ctrl nebo Alt , jako je kliknutí na tlačítko v parametru MouseEventArgs
. Tento parametr nemusíte zadávat při volání metody; Modul runtime Blazor ho přidá automaticky. Tento parametr můžete dotazovat v obslužné rutině události. Následující kód zvýší čítač zobrazený v předchozím příkladu o pět, pokud uživatel stiskne klávesu Ctrl současně s kliknutím na tlačítko:
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount(MouseEventArgs e)
{
if (e.CtrlKey) // Ctrl key pressed as well
{
currentCount += 5;
}
else
{
currentCount++;
}
}
}
Jiné události poskytují různé EventArgs
parametry. Například událost předá KeyboardEventArgs
parametr, který označuje, @onkeypress
kterou klávesu uživatel stiskl. Pokud některé události MODELU DOM nepotřebujete, můžete parametr vynechat EventArgs
z metody zpracování událostí.
Vysvětlení zpracování událostí v JavaScriptu a zpracování událostí pomocí Blazoru
Tradiční webová aplikace používá JavaScript k zachycení a zpracování událostí. Funkci vytvoříte jako součást elementu skriptu> HTML <a pak ji uspořádáte tak, aby volala tuto funkci, když dojde k události. Pro porovnání s předchozím příkladem Blazor následující kód ukazuje fragment ze stránky HTML, která zvýší hodnotu a zobrazí výsledek pokaždé, když uživatel vybere tlačítko Kliknout na mě . Kód používá knihovnu jQuery pro přístup k dom.
<p id="currentCount">Current count: 0</p>
<button class="btn btn-primary" onclick="incrementCount()">Click me</button>
<!-- Omitted for brevity -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
var currentCount = 0;
function incrementCount() {
currentCount++;
$('#currentCount').html('Current count:' + currentCount);
}
</script>
Kromě syntaktických rozdílů ve dvou verzích obslužné rutiny události byste měli poznamenat následující funkční rozdíly:
- JavaScript nemá před název události znaménko
@
, nejedná se o direktivu Blazor. - V kódu Blazor zadáte název metody zpracování událostí, když ji připojíte k události. V JavaScriptu napíšete příkaz, který volá metodu zpracování událostí; zadáte zaokrouhlené závorky a všechny požadované parametry.
- Nejdůležitější je, že obslužná rutina události JavaScriptu běží v prohlížeči v klientovi. Pokud vytváříte aplikaci Blazor Server App, obslužná rutina události Blazor se spustí na serveru a aktualizuje prohlížeč pouze o všechny změny provedené v uživatelském rozhraní po dokončení obslužné rutiny události. Kromě toho mechanismus Blazor umožňuje obslužné rutině události přístup ke statickým datům sdíleným mezi relacemi; JavaScriptový model ne. Zpracování některých často se vyskytujících událostí, například
@onmousemove
může způsobit, že se uživatelské rozhraní ztlumí, protože vyžadují odezvu sítě na server. Události, jako jsou tyto, můžete raději zpracovávat v prohlížeči pomocí JavaScriptu.
Důležité
S modelem DOM můžete pracovat pomocí kódu JavaScriptu z obslužné rutiny události a také pomocí kódu Blazor v jazyce C#. Blazor ale udržuje vlastní kopii modelu DOM, která se v případě potřeby používá k aktualizaci uživatelského rozhraní. Pokud ke změně stejných prvků v dom použijete JavaScript a Blazor, riskujete poškození dom a případně ohrožení ochrany osobních údajů a zabezpečení dat ve webové aplikaci.
Asynchronní zpracování událostí
Ve výchozím nastavení jsou obslužné rutiny událostí Blazor synchronní. Pokud obslužná rutina události provede potenciálně dlouhou operaci, jako je volání webové služby, vlákno, na kterém se obslužná rutina události spustí, bude blokováno, dokud operace nebude dokončena. To může vést k špatné odezvě v uživatelském rozhraní. Chcete-li s tím bojovat, můžete určit metodu obslužné rutiny události jako asynchronní. Použijte klíčové slovo jazyka C# async
. Metoda musí vrátit Task
objekt. Potom můžete pomocí operátoru await
uvnitř metody obslužné rutiny události zahájit všechny dlouhotrvající úlohy na samostatném vlákně a uvolnit aktuální vlákno pro jinou práci. Po dokončení dlouhotrvající úlohy se obslužná rutina události obnoví. Následující příklad obslužné rutiny události spouští časově náročnou metodu asynchronně:
<button @onclick="DoWork">Run time-consuming operation</button>
@code {
private async Task DoWork()
{
// Call a method that takes a long time to run and free the current thread
var data = await timeConsumingOperation();
// Omitted for brevity
}
}
Poznámka:
Podrobné informace o vytváření asynchronních metod v jazyce C# najdete v tématu Asynchronní programovací scénáře.
Nastavení fokusu na element MODELU DOM pomocí události
Na stránce HTML může uživatel zarážku mezi prvky a fokus přirozeně cestovat v pořadí, ve kterém se prvky HTML zobrazují na stránce. V některých případech může být nutné tuto sekvenci přepsat a vynutit, aby uživatel navštívil určitý prvek.
Nejjednodušší způsob, jak tuto úlohu provést, je použít metodu FocusAsync
. Jedná se o metodu instance objektu ElementReference
. Položka ElementReference
, na kterou chcete nastavit fokus, by měla odkazovat. Označíte odkaz na prvek s atributem @ref
a vytvoříte objekt jazyka C# se stejným názvem v kódu.
V následujícím příkladu obslužná rutina @onclick
události pro <prvek button> nastaví fokus na <vstupní> prvek. Obslužná rutina @onfocus
události vstupního> <prvku zobrazí zprávu "Přijato fokus", když prvek získá fokus. Vstupní <> prvek se odkazuje prostřednictvím InputField
proměnné v kódu:
<button class="btn btn-primary" @onclick="ChangeFocus">Click me to change focus</button>
<input @ref=InputField @onfocus="HandleFocus" value="@data"/>
@code {
private ElementReference InputField;
private string data;
private async Task ChangeFocus()
{
await InputField.FocusAsync();
}
private async Task HandleFocus()
{
data = "Received focus";
}
Následující obrázek ukazuje výsledek, když uživatel vybere tlačítko:
Poznámka:
Aplikace by měla směrovat fokus pouze na konkrétní ovládací prvek z konkrétního důvodu, například požádat uživatele, aby upravil vstup po chybě. Nepoužívejte zaměření k vynucení procházení prvků na stránce uživatele v pevném pořadí; to může být velmi frustrující pro uživatele, který se může chtít vrátit k prvkům, aby změnil svůj vstup.
Zápis vložených obslužných rutin událostí
Jazyk C# podporuje výrazy lambda. Výraz lambda umožňuje vytvořit anonymní funkci. Výraz lambda je užitečný, pokud máte jednoduchou obslužnou rutinu události, kterou nemusíte opakovaně používat jinde na stránce nebo komponentě. V příkladu počátečního počtu kliknutí zobrazených na začátku této lekce můžete metodu IncrementCount
odebrat a místo toho nahradit volání metody výrazem lambda, který provádí stejnou úlohu:
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="() => currentCount++">Click me</button>
@code {
private int currentCount = 0;
}
Poznámka:
Podrobnosti o tom, jak výrazy lambda fungují, najdete v tématu Výrazy lambda a anonymní funkce.
Tento přístup je také užitečný, pokud chcete zadat další argumenty pro metodu zpracování událostí. V následujícím příkladu metoda HandleClick
přebírá MouseEventArgs
parametr stejným způsobem jako běžná obslužná rutina události kliknutí, ale také přijímá řetězcový parametr. Metoda zpracovává událost kliknutí jako předtím, ale také zobrazí zprávu v uživateli stisknutou klávesu Ctrl . Výraz lambda volá metodu HandleCLick
, předává MouseEventArgs
parametr (mouseEvent
) a řetězec.
@page "/counter"
@inject IJSRuntime JS
<h1>Counter</h1>
<p id="currentCount">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick='mouseEvent => HandleClick(mouseEvent, "Hello")'>Click me</button>
@code {
private int currentCount = 0;
private async Task HandleClick(MouseEventArgs e, string msg)
{
if (e.CtrlKey) // Ctrl key pressed as well
{
await JS.InvokeVoidAsync("alert", msg);
currentCount += 5;
}
else
{
currentCount++;
}
}
}
Poznámka:
Tento příklad používá funkci JavaScriptu alert
k zobrazení zprávy, protože v Blazoru neexistuje žádná ekvivalentní funkce. K volání JavaScriptu z kódu Blazor použijete zprostředkovatele JavaScriptu. Podrobnosti o této technice jsou předmětem samostatného modulu.
Přepsání výchozích akcí DOM pro události
Několik událostí MODELU DOM má výchozí akce, které se spouštějí při výskytu události bez ohledu na to, jestli je pro tuto událost dostupná obslužná rutina události. Například @onkeypress
událost vstupního <> prvku vždy zobrazí znak, který odpovídá klávesě, kterou uživatel stiskl, a stisknutou klávesou. V dalším příkladu @onkeypress
se událost použije k převodu vstupu uživatele na velká písmena. Pokud navíc uživatel zadá @
znak, obslužná rutina události zobrazí výstrahu:
<input value=@data @onkeypress="ProcessKeyPress"/>
@code {
private string data;
private async Task ProcessKeyPress(KeyboardEventArgs e)
{
if (e.Key == "@")
{
await JS.InvokeVoidAsync("alert", "You pressed @");
}
else
{
data += e.Key.ToUpper();
}
}
}
Pokud tento kód spustíte a stisknete klávesu @
, zobrazí se upozornění, ale @
znak se přidá také do vstupu. Přidání znaku @
je výchozí akcí události.
Pokud chcete potlačit zobrazení tohoto znaku ve vstupním poli, můžete výchozí akci přepsat atributem preventDefault
události, například takto:
<input value=@data @onkeypress="ProcessKeyPress" @onkeypress:preventDefault />
Událost se stále aktivuje, ale provede se pouze akce definované obslužnou rutinou události.
Některé události v podřízené elementu DOM mohou aktivovat události v jejich nadřazených prvcích. V následujícím příkladu <element div> obsahuje obslužnou rutinu @onclick
události. > Tlačítko <uvnitř div> má vlastní @onclick
obslužnou rutinu <události. Kromě toho <div> obsahuje <vstupní> prvek:
<div @onclick="HandleDivClick">
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<input value=@data @onkeypress="ProcessKeyPress" @onkeypress:preventDefault />
</div>
@code {
private async Task HandleDivClick()
{
await JS.InvokeVoidAsync("alert", "Div click");
}
private async Task ProcessKeyPress(KeyboardEventArgs e)
{
// Omitted for brevity
}
private int currentCount = 0;
private void IncrementCount(MouseEventArgs e)
{
// Omitted for brevity
}
}
Když se aplikace spustí, uživatel klikne na libovolný prvek (nebo prázdné místo) v oblasti obsazené elementem <div> , metoda HandleDivClick
se spustí a zobrazí zprávu. Pokud uživatel tlačítko vybere Click me
, IncrementCount
spustí se metoda následovaná HandleDivClick
; @onclick
událost rozšíří strom MODELU DOM. <Pokud byl div> součástí jiného prvku, který také zpracovával @onclick
událost, tato obslužná rutina události by se také spustila a tak dále, do kořene stromu MODELU DOM. Toto zvýšení počtu událostí stopPropagation
můžete omezit pomocí atributu události, jak je znázorněno zde:
<div @onclick="HandleDivClick">
<button class="btn btn-primary" @onclick="IncrementCount" @onclick:stopPropagation>Click me</button>
<!-- Omitted for brevity -->
</div>
Zpracování událostí napříč komponentami pomocí eventCallbacku
Stránka Blazor může obsahovat jednu nebo více součástí Blazoru a komponenty lze vnořit do vztahu nadřazeného a podřízeného objektu. Událost v podřízené komponentě může aktivovat metodu obslužné rutiny události v nadřazené komponentě pomocí EventCallback
. Zpětné volání odkazuje na metodu v nadřazené komponentě. Podřízená komponenta může metodu spustit vyvoláním zpětného volání. Tento mechanismus se podobá použití delegate
metody odkaz na metodu v aplikaci jazyka C#.
Zpětné volání může mít jeden parametr. EventCallback
je obecný typ. Parametr typu určuje typ argumentu předaného zpětnému volání.
Jako příklad zvažte následující scénář. Chcete vytvořit komponentu s názvem TextDisplay
, která uživateli umožňuje zadat vstupní řetězec a tento řetězec nějakým způsobem transformovat. Můžete ho převést na velká, malá, malá, smíšená, vyfiltrovat z něj znaky nebo provést jiný typ transformace. Když ale napíšete kód pro komponentu TextDisplay
, nevíte, co bude proces transformace, a místo toho chcete tuto operaci odložit na jinou komponentu. Následující kód ukazuje komponentu TextDisplay
. Poskytuje vstupní řetězec ve formě vstupního <> prvku, který uživateli umožňuje zadat textovou hodnotu.
@* TextDisplay component *@
@using WebApplication.Data;
<p>Enter text:</p>
<input @onkeypress="HandleKeyPress" value="@data" />
@code {
[Parameter]
public EventCallback<KeyTransformation> OnKeyPressCallback { get; set; }
private string data;
private async Task HandleKeyPress(KeyboardEventArgs e)
{
KeyTransformation t = new KeyTransformation() { Key = e.Key };
await OnKeyPressCallback.InvokeAsync(t);
data += t.TransformedKey;
}
}
Komponenta TextDisplay
používá EventCallback
objekt s názvem OnKeyPressCallback
. Kód v HandleKeypress
metodě vyvolá zpětné volání. Obslužná rutina @onkeypress
události se spustí při každém stisknutí klávesy a zavolá metodu HandleKeypress
. Metoda HandleKeypress
vytvoří KeyTransformation
objekt pomocí klávesy, které uživatel stiskl a předá tento objekt jako parametr zpětnému volání. Typ KeyTransformation
je jednoduchá třída se dvěma poli:
namespace WebApplication.Data
{
public class KeyTransformation
{
public string Key { get; set; }
public string TransformedKey { get; set; }
}
}
Pole key
obsahuje hodnotu zadaná uživatelem a TransformedKey
pole bude po zpracování obsahovat transformovanou hodnotu klíče.
V tomto příkladu EventCallback
je objekt parametrem komponenty a jeho hodnota je zadána při vytvoření komponenty. Tuto akci provádí jiná komponenta s názvem TextTransformer
:
@page "/texttransformer"
@using WebApplication.Data;
<h1>Text Transformer - Parent</h1>
<TextDisplay OnKeypressCallback="@TransformText" />
@code {
private void TransformText(KeyTransformation k)
{
k.TransformedKey = k.Key.ToUpper();
}
}
Komponenta TextTransformer
je stránka Blazor, která vytvoří instanci TextDisplay
komponenty. OnKeypressCallback
Naplní parametr odkazem na metodu TransformText
v části kódu stránky. Metoda TransformText
přebírá KeyTransformation
objekt zadaný jako jeho argument a vyplní TransformedKey
vlastnost hodnotou nalezenou ve Key
vlastnosti převedené na velká písmena. Následující diagram znázorňuje tok řízení, když uživatel zadá hodnotu do vstupního <> pole v TextDisplay
komponentě zobrazené na TextTransformer
stránce:
Výhodou tohoto přístupu je, že komponentu TextDisplay
můžete použít s libovolnou stránkou, která poskytuje zpětné volání parametru OnKeypressCallback
. Mezi displejem a zpracováním je úplné oddělení. Můžete přepnout metodu TransformText
pro jakékoli jiné zpětné volání, které odpovídá podpisu EventCallback
parametru v komponentě TextDisplay
.
Zpětné volání můžete připojit k obslužné rutině události přímo bez použití zprostředkující metody, pokud je zpětné volání zadáno s odpovídajícím EventArgs
parametrem. Podřízená komponenta může například odkazovat na zpětné volání, které může zpracovávat události myši, například @onclick
takto:
<button @onclick="OnClickCallback">
Click me!
</button>
@code {
[Parameter]
public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}
V tomto případě EventCallback
přebírá MouseEventArgs
parametr typu, takže ho lze zadat jako obslužnou rutinu @onclick
události.