Připojení kódu C# k událostem MODELU DOM pomocí obslužných rutin událostí Blazor
- 5 min
Většina elementů HTML zveřejňuje události, které se aktivují, když dojde k něčemu významnému. Například po dokončení načítání stránky uživatel klikne na tlačítko nebo se změní 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 získáte podrobný pohled 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. Prvek <p> na stránce zobrazuje hodnotu čítačové proměnné:
@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á @onkeypress parametr, který označuje, KeyboardEventArgs 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ředponu názvu události pomocí znaménka
@; není to direktiva 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, což JavaScriptový model neumožňuje. Zpracování některých často se vyskytujících událostí, například
@onmousemovemůž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.
Important
S modelem DOM můžete pracovat pomocí kódu JavaScriptu z obslužné rutiny události a pomocí kódu C# Blazor. Blazor ale udržuje vlastní kopii modelu DOM, která se v případě potřeby používá k aktualizaci uživatelského rozhraní. Pokud používáte k úpravě stejných prvků ve struktuře DOM kód JavaScript a Blazor, riskujete poškození této struktury. Můžete také ohrozit ochranu 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 provádí potenciálně dlouhou operaci, jako je volání webové služby, vlákno, na kterém se obslužná rutina události spouští, je blokována, dokud se operace nekončí. Tato situace může vést k špatné odezvě v uživatelském rozhraní. Chcete-li řešit tento problém, můžete určit obslužnou metodu 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 ukazuje obslužnou rutinu události, která 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
}
}
Note
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 . Tato metoda je metoda 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:
Note
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 fokus k vynucení, aby uživatel procházel prvky na stránce v pevném pořadí. Tento návrh může být 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;
}
Note
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, pokud uživatel stiskne 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++;
}
}
}
Note
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 událost @onkeypress pro prvek <vstupu> vždy zobrazí znak, který odpovídá klávese stisknuté uživatelem, a poté zpracuje stisk klávesy. 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 provádí se pouze akce definované obslužným programem 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í > obslužnou rutinu @onclickudá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> , spustí se metoda HandleDivClick a zobrazí zprávu. Pokud uživatel vybere tlačítko Click me, spustí se metoda IncrementCount, a následně HandleDivClick; událost @onclick se rozšíří do DOM stromu.
<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 nějakým způsobem tento řetězec transformovat. Můžete ho převést na velká písmena, malá písmena, smíšená písmena, filtrovat znaky z něj nebo provést jiný typ transformace. Když ale napíšete kód pro komponentu TextDisplay , nevíte, co bude proces transformace. 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 obsahuje transformovanou hodnotu klíče po zpracování.
V tomto příkladu EventCallback je objekt parametrem komponenty a jeho hodnota je zadána při vytvoření komponenty. Komponenta s názvem TextTransformer provede tuto akci:
@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.