Označení směrovaných událostí jako zpracovaných a zpracování tříd

Obslužné rutiny směrované události mohou označovat událost zpracovanou v datech události. Zpracování události bude efektivně zkrátit trasu. Zpracování tříd je programovací pojem, který je podporován směrovanými událostmi. Obslužná rutina třídy má příležitost zpracovat konkrétní směrovanou událost na úrovni třídy pomocí obslužné rutiny, která je vyvolána před jakoukoliv obslužnou rutinou instance v jakékoli instanci třídy.

Předpoklady

Toto téma se seznámí s koncepty představenými v přehledu směrovaných událostí.

Kdy označit události jako zpracovávané

Při nastavení hodnoty Handled vlastnosti na hodnotu true v datech události pro směrovanou událost se označuje jako "označení události, která se zpracovává". Neexistuje žádné absolutní pravidlo, pokud byste měli označit směrované události jako zpracovávané, buď jako autora aplikace, nebo jako autor ovládacího prvku, který reaguje na stávající směrované události nebo implementuje nové směrované události. Ve většině případů by koncept "zpracovávaný" byl v datech události směrované události použit jako omezený protokol pro vlastní odpovědi aplikace na různé směrované události vystavené v WPF rozhraních API a také pro všechny vlastní směrované události. Dalším způsobem, jak vzít v úvahu "zpracovávaný" problém, je, že byste měli obecně označit směrovanou událost, která je zpracována, pokud kód odpověděl na směrovanou událost významným a relativně úplným způsobem. Obvykle by neměla existovat více než jedna významná odpověď, která vyžaduje samostatné implementace obslužných rutin pro každý výskyt události s jedním směrováním. Je-li zapotřebí více odpovědí, je nutné implementovat potřebný kód prostřednictvím logiky aplikace, která je zřetězena v rámci jedné obslužné rutiny, nikoli pomocí směrovaného systému událostí pro přesměrování. Pojem "značný" je také subjektivní a závisí na vaší aplikaci nebo kódu. Obecně platí, že některé "významné reakce" jsou například: nastavení fokusu, změna veřejného stavu, nastavení vlastností, které ovlivňují vizuální znázornění a vyvolání dalších nových událostí. Mezi příklady nepodstatných odpovědí patří: Změna privátního stavu (bez vizuálního dopadu nebo programové rereprezentace), protokolování událostí nebo prohlížení argumentů události a volba nereakce na ni.

Chování směrovaného systému událostí posiluje tento model "významná reakce" pro použití zpracovávaných stavů směrované události, protože obslužné rutiny, XAML nebo společný podpis, nejsou AddHandler vyvolány v reakci na směrovanou událost, kde jsou již data události označena jako zpracovaná. handledEventsToo AddHandler(RoutedEvent, Delegate, Boolean) Aby bylo možné zpracovávat směrované události, které jsou označeny předchozími účastníky v trase události, je nutné projít další úsilím o přidání obslužné rutiny s verzí parametru ().

V některých případech ovládací prvky samy označují určité směrované události jako zpracovávané. Zpracovaná směrovaná událost představuje rozhodnutí na základě WPF autorů ovládacích prvků, že akce ovládacího prvku v reakci na směrovanou událost jsou významné nebo dokončené jako součást implementace ovládacího prvku a událost nepotřebuje žádné další zpracování. Obvykle je to provedeno přidáním obslužné rutiny třídy pro událost nebo přepsáním jedné z virtuálních obslužných rutin třídy, které existují v základní třídě. V případě potřeby můžete toto zpracování událostí dál obejít; Další informace najdete v tématu práce s potlačením událostí pomocí ovládacích prvků dále v tomto tématu.

Náhled (tunelování) události vs. šíření událostí a zpracování událostí

Směrované události ve verzi Preview jsou události, které následují po tunelové trase prostřednictvím stromu elementu. "Preview" vyjádřená v konvenci pojmenování je orientační obecné zásady pro vstupní události, které směrované události ve verzi Preview (TUNELING) jsou vyvolány před ekvivalentní událostí směrovaného probublávání. Vstupní směrované události, které mají dvojici tunelování a probublávání, mají také zvláštní logiku zpracování. Pokud je nasměrovaná událost tunelového propojení/náhledu označena jako zpracovávaná naslouchacím programem událostí, pak bude směrované směrná událost označena jako zpracovaná, a to i před tím, než přijme všechny posluchače směrované směrované události. Směrované tunelování a probublávání směrované události jsou technicky samostatné události, ale záměrně sdílejí stejnou instanci dat událostí, aby bylo možné toto chování povolit.

Propojení mezi tunelovým propojením a směrovanými událostmi je provedeno interní implementací způsobu, jakým daná WPF Třída vyvolává své vlastní deklarované směrované události a jedná se o true pro spárované vstupní směrované události. Pokud však tato implementace na úrovni třídy neexistuje, neexistuje spojení mezi událostí směrovaného tunelového propojení a probublávání směrované události, která sdílí schéma pojmenování: bez takové implementace by by byly dvě zcela oddělené směrované události a nemusely být vyvolány v sekvenci nebo sdílet data události.

Další informace o tom, jak implementovat dvojice událostí směrovaného tunelového propojení nebo bublinového vstupu ve vlastní třídě, najdete v tématu Vytvoření vlastní směrované události.

Obslužné rutiny tříd a obslužné rutiny instancí

Směrované události uvažují dva různé typy posluchačů k události: naslouchací procesy tříd a naslouchací procesy instancí. Naslouchací procesy tříd existují, protože typy se nazývají konkrétní EventManager rozhraní API, RegisterClassHandler , ve svém statickém konstruktoru nebo přepsaly virtuální metodu obslužné rutiny třídy z základní třídy elementu. Naslouchací procesy instance jsou konkrétní instance nebo prvky třídy, kde byl k této směrované události připojen jeden nebo více obslužných rutin voláním AddHandler . Stávající WPF směrované události volají AddHandler jako součást obálky události modulu CLR (Common Language Runtime) přidání {} a odebrání {} implementací události, což je také způsob, jakým je povolen jednoduchý XAML mechanismus připojení obslužných rutin událostí prostřednictvím syntaxe atributu. Proto i jednoduché XAML použití je nakonec rovno AddHandler volání.

Prvky ve vizuálním stromu jsou zkontrolovány pro registrované implementace obslužných rutin. Obslužné rutiny jsou potenciálně vyvolány v rámci trasy, v pořadí, které je podstatou typu strategie směrování pro tuto směrovanou událost. Například probublávání směrované události nejprve vyvolá tyto obslužné rutiny, které jsou připojeny ke stejnému prvku, který vyvolal směrovanou událost. Pak směrované událost "bubliny" na další nadřazený prvek a tak dále, dokud není dosaženo kořenového prvku aplikace.

Z perspektivy kořenového prvku v trase probublávání, pokud zpracování tříd nebo libovolný prvek blíže zdroji směrované události vyvolávají obslužné rutiny, které označují argumenty události jako zpracovávané, nejsou vyvolány obslužné rutiny kořenových elementů a směrování událostí je před dosažením tohoto kořenového prvku účinně zkráceno. Nicméně trasa není zcela zastavena, protože obslužné rutiny lze přidat pomocí zvláštního podmíněného řízení, které by měly být vyvolány i v případě, že obslužná rutina třídy nebo obslužná rutina instance označila směrovanou událost jako zpracovanou. To je vysvětleno v tématu Přidání obslužných rutin instance, které jsou vyvolány, i když jsou události označeny jako zpracované, dále v tomto tématu.

Na hlubší úrovni než v případě trasy události, existuje také potenciálně více obslužných rutin třídy působících na jakékoli dané instanci třídy. Důvodem je, že model zpracování tříd pro směrované události umožňuje všem možným třídám v hierarchii tříd pro každou směrovanou událost zaregistrovat svoji vlastní obslužnou rutinu třídy. Každá obslužná rutina třídy je přidána do interního úložiště a při sestavení trasy události pro aplikaci jsou všechny obslužné rutiny třídy přidány do trasy události. Obslužné rutiny třídy jsou přidány do trasy tak, že je nejprve vyvolána největší odvozená třída a obslužné rutiny třídy z každé následující základní třídy jsou vyvolány v dalším. Obecně nejsou obslužné rutiny tříd registrovány tak, že reagují na směrované události, které již byly označeny jako zpracované. Proto tento mechanismus manipulace třídy umožňuje jednu ze dvou možností:

  • Odvozené třídy mohou doplňovat zpracování tříd, která je zděděna ze základní třídy přidáním obslužné rutiny, která neoznačuje zpracování směrované události, protože obslužná rutina základní třídy bude vyvolána každou za každou za obslužnou rutinu odvozené třídy.

  • Odvozené třídy mohou nahradit zpracování tříd ze základní třídy přidáním obslužné rutiny třídy, která označuje zpracování směrované události. Měli byste být opatrní s tímto přístupem, protože bude potenciálně měnit zamýšlený návrh základního ovládacího prvku v oblastech, jako je vizuální vzhled, stavová logika, zpracování vstupu a zpracování příkazů.

Zpracování tříd směrovaných událostí pomocí základních tříd ovládacích prvků

U každého daného uzlu elementu v trase události mají naslouchací procesy třídy možnost reagovat na směrovanou událost před tím, než může kterýkoli naslouchací proces instancí elementu. Z tohoto důvodu obslužné rutiny třídy jsou někdy použity pro potlačení směrovaných událostí, které konkrétní implementace třídy ovládacího prvku nechce rozšířit další, nebo pro poskytnutí speciálního zpracování této směrované události, která je funkcí třídy. Například třída může vyvolat svou vlastní událost specifickou pro třídu, která obsahuje konkrétnější informace o tom, co některá podmínka vstupu uživatele znamená v kontextu této konkrétní třídy. Implementace třídy pak může označit obecnější směrované události jako zpracovávané. Obslužné rutiny třídy jsou obvykle přidány tak, že nejsou vyvolány pro směrované události, kde již byla označena zpracovaná data události, ale v případě neobvyklého případu existuje také RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) podpis, který zaregistruje obslužné rutiny tříd, které mají vyvolat, i když jsou směrované události označeny jako zpracované.

Virtuální obslužné rutiny třídy

Některé prvky, zejména základní prvky, jako UIElement je, vystavení prázdné "on *" událost "a" * událost náhledu události ", které odpovídají jejich seznamu veřejných směrovaných událostí. Tyto virtuální metody lze přepsat pro implementaci obslužné rutiny třídy pro tuto směrovanou událost. Základní třídy prvků registrují tyto virtuální metody jako obslužné rutiny třídy pro každou takovou směrovanou událost pomocí RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) postupu popsaného výše. *Virtuální metody události on zjednodušují implementaci zpracování tříd pro příslušné směrované události, aniž by vyžadovaly speciální inicializaci ve statických konstruktorech pro každý typ. Například můžete přidat zpracování tříd pro DragEnter událost v libovolné UIElement odvozené třídy přepsáním OnDragEnter virtuální metody. V rámci přepsání můžete zpracovat směrovanou událost, vyvolat další události, iniciovat logiku specifickou pro třídu, která může měnit vlastnosti prvku na instancích nebo jakoukoli kombinaci těchto akcí. Obecně byste měli volat základní implementaci v takových přepsáních i v případě, že označíte událost, která je zpracována. Důrazně doporučujeme volání základní implementace, protože virtuální metoda je na základní třídě. Standardní chráněný virtuální model, který volá základní implementace z každého virtuálního počítače, v podstatě nahrazuje a paralelně podobá podobný mechanismus, který je nativní pro směrování zpracování tříd událostí, přičemž obslužné rutiny třídy pro všechny třídy v hierarchii tříd jsou volány na jakékoli dané instanci, počínaje pomocí nejvyšší odvozené třídy a pokračování obslužné rutiny základní třídy. Je nutné vynechat volání základní implementace pouze v případě, že vaše třída má záměrné požadavky na změnu logiky zpracování základní třídy. Bez ohledu na to, zda zavoláte základní implementaci před nebo po přepsání kódu, bude záviset na povaze vaší implementace.

Zpracování třídy událostí vstupu

Virtuální metody obslužné rutiny třídy jsou všechny zaregistrované tak, aby se vyvolaly jenom v případech, kdy všechna sdílená data událostí ještě nejsou označená jako zpracovaná. V případě jedinečnosti vstupních událostí jsou také tunelování a šíření verzí obvykle vyvolány v sekvenci a sdílejí data události. To má za následek, že pro danou dvojici obslužných rutin třídy vstupních událostí, kde jedna je verze tunelování a druhá je probublávání verze, nechcete, aby byla událost zpracována okamžitě. Pokud implementujete metodu tunelování pro zpracování virtuální metody k označení zpracování události, která zabrání vyvolání obslužné rutiny třídy (a také zabránění jakýmkoli normálně registrovaným obslužným rutinám instance pro vyvolání události tunelu nebo probublávání).

Jakmile je zpracování třídy na uzlu dokončeno, jsou považovány za naslouchací procesy instance.

Přidání obslužných rutin instancí, které jsou vyvolány, i když jsou události označeny jako zpracované

AddHandlerMetoda poskytuje konkrétní přetížení, které umožňuje přidat obslužné rutiny, které budou vyvolány systémem událostí vždy, když událost dosáhne elementu manipulace v trase, i v případě, že nějaká jiná obslužná rutina již upravila data události k označení této události jako zpracovaného. To se obvykle neprovádí. Obecně lze obslužné rutiny zapsat pro úpravu všech oblastí kódu aplikace, které mohou být ovlivněny událostí, bez ohledu na to, kde byly zpracovány ve stromové struktuře elementu, i když je požadováno více konečných výsledků. Také obvykle existuje pouze jeden prvek, který musí na tuto událost reagovat, a příslušná logika aplikace již proběhla. Ale handledEventsToo přetížení je k dispozici pro výjimečné případy, kdy některý jiný element ve stromové struktuře elementu nebo skládání ovládacího prvku již označil událost jako zpracovanou, ale jiné prvky ve stromové struktuře elementu (v závislosti na trase) stále chtějí mít vyvolané vlastní obslužné rutiny.

Kdy označit zpracovávané události jako neošetřené

Obecně směrované události, které jsou označeny jako zpracované, by neměly být označeny jako neošetřené ( Handled nastavení zpět na false ), a to i pomocí obslužných rutin, které fungují handledEventsToo . Nicméně některé vstupní události mají na vysoké úrovni a reprezentace událostí nižší úrovně, které se mohou překrývat, pokud se událost vysoké úrovně zobrazuje na jedné pozici stromu a událost nízké úrovně na jiné pozici. Zvažte například případ, kdy podřízený prvek naslouchá události klíče vysoké úrovně, například TextInput když nadřazený prvek naslouchá události nízké úrovně, jako je například KeyDown . Pokud nadřazený element zpracovává událost nízké úrovně, může být událost vyšší úrovně potlačena i v podřízeném elementu, který by intuitivní by měl mít první příležitost zpracovat událost.

V těchto situacích může být nutné přidat obslužné rutiny do nadřazených prvků a podřízených prvků pro událost nízké úrovně. Implementace obslužné rutiny podřízeného elementu může označit událost nízké úrovně jako zpracovanou, ale implementace obslužné rutiny nadřazeného elementu by ji znovu nastavila tak, aby další prvky stromu (stejně jako událost vysoké úrovně) mohly mít možnost reagovat. Tato situace by měla být poměrně zřídka.

Úmyslné potlačení vstupních událostí pro skládání ovládacích prvků

Hlavní scénář, ve kterém se používá zpracování tříd směrovaných událostí, je pro vstupní události a složené ovládací prvky. Složený ovládací prvek je podle definice tvořená několika praktickými ovládacími prvky nebo řídicími základními třídami. Autor ovládacího prvku často chce amalgamate všechny možné vstupní události, které mohou vyvolat jednotlivé dílčí komponenty, aby bylo možné nahlásit celý ovládací prvek jako jednotný zdroj událostí. V některých případech může autor ovládacího prvku chtít potlačit události z komponent zcela nebo nahradit událost definovanou komponentou, která poskytuje další informace nebo implikuje konkrétnější chování. Kanonický příklad, který je okamžitě viditelný pro všechny autory komponenty, je způsob, jakým Windows Presentation Foundation (WPF) Button událost myši, která bude nakonec přeložena na intuitivní událost, která má všechna tlačítka: Click událost.

ButtonZákladní třída ( ButtonBase ) je odvozena z Control toho, ze které se dále odvozují FrameworkElement a a UIElement většina infrastruktury událostí potřebná pro zpracování vstupu řízení je k dispozici na UIElement úrovni. Konkrétně UIElement zpracovává obecné Mouse události, které zpracovávají testy přístupů pro ukazatel myši v rámci jeho hranic, a poskytuje odlišné události pro nejběžnější akce tlačítek, jako je například MouseLeftButtonDown . UIElement poskytuje také prázdný virtuální OnMouseLeftButtonDown jako obslužnou rutinu pro předregistrovanou třídu pro MouseLeftButtonDown a ButtonBase Přepisuje ji. Podobně ButtonBase používá obslužné rutiny třídy pro MouseLeftButtonUp . V přepsáních, kterým jsou předány data události, implementace označí tuto RoutedEventArgs instanci jako zpracovanou nastavením Handled na true a stejnými daty události je to, co pokračuje ve zbývající části trasy na jiné obslužné rutiny tříd a také obslužné rutiny instancí nebo metody pro řízení událostí. OnMouseLeftButtonUpPřepsání také příště vyvolá Click událost. Konečný výsledek pro většinu posluchačů bude, že MouseLeftButtonDown události a MouseLeftButtonUp jsou "zmizí" a místo toho jsou nahrazeny Click událostí, která má větší význam, protože je známo, že tato událost vznikla z tlačítka true a nikoli z nějakého složeného kusu tlačítka nebo z nějakého jiného prvku.

Práce s potlačením událostí pomocí ovládacích prvků

V některých případech může toto chování při potlačení události v rámci jednotlivých ovládacích prvků narušit s některými obecnější záměry logiky zpracování událostí pro vaši aplikaci. Například pokud z nějakého důvodu má aplikace obslužnou rutinu pro MouseLeftButtonDown umístění v kořenovém elementu aplikace, všimnete si, že jakékoli kliknutí myší na tlačítko by nebylo možné vyvolat MouseLeftButtonDown nebo MouseLeftButtonUp obslužné rutiny na kořenové úrovni. Vlastní událost sama provedla bublinu (znovu, trasy událostí nejsou ve skutečnosti ukončeny, ale směrovaný systém událostí po označení zpracování změní jejich chování volání obslužných rutin. Když směrované událost dosáhla tlačítka, ButtonBase zpracovává zpracování třídy označené jako MouseLeftButtonDown zpracované, protože chtěla nahradit Click událost větším významem. Proto by se žádná standardní MouseLeftButtonDown obslužná rutina dále vyvolala. Existují dva postupy, které můžete použít k zajištění toho, aby byly obslužné rutiny vyvolány v této situaci.

Prvním postupem je úmyslné přidání obslužné rutiny pomocí handledEventsToo signatury AddHandler(RoutedEvent, Delegate, Boolean) . Omezení tohoto přístupu je, že tato technika pro připojení obslužné rutiny události je možné pouze z kódu, nikoli z značek. Jednoduchá syntaxe zadání názvu obslužné rutiny události jako hodnoty atributu události prostřednictvím nepovoluje XAML (Extensible Application Markup Language) Toto chování.

Druhá technika funguje pouze pro vstupní události, kde jsou párovány verze tunelování a šíření směrovaných událostí. Pro tyto směrované události můžete místo toho přidat obslužné rutiny do ekvivalentní směrované události verze Preview/Tunneling. Tato směrované událost bude tunelem směrována z kořenového adresáře, takže kód pro zpracování třídy tlačítka by ho nezachytil, předpokládá se, že jste připojili obslužnou rutinu Preview na některé úrovni nadřazeného prvku ve stromu prvků aplikace. Pokud použijete tento přístup, buďte opatrní při označování všech zpracovaných událostí ve verzi Preview. Pro příklad zadaný při PreviewMouseLeftButtonDown zpracovávání u kořenového prvku, pokud jste označili událost jako Handled v implementaci obslužné rutiny, byste událost skutečně potlačili Click . To obvykle není žádoucí chování.

Viz také