Jedním z nových konceptů v Dynamics AX 2012 jsou události (events) a jejich zpracování (event handling). Dlouho dopředu bylo avizováno, že bude možné “navěsit” obsluhu události (event handler) před a za každou metodu, tak se pojďme podívat, co to znamená v praxi.
Terminologická poznámka: Event handler je v české literatuře obvykle označován jako “obsluha události” nebo “ovladač události”, mnohdy se ale používá prostě “handler”.
Na metodách tříd a tabulek lze z kontextové nabídky zvolit New Event Handler Subscription (platí pro instanční i statické metody, ne však pro display a edit metody). Tím je vytvořen poduzel dané metody, defaultně nazvaný EventHandler1.
Event Handler Subscription definuje třídu a metodu, která bude spuštěna, zda bude spuštěna před nebo za obsluhovanou metodou a zda je volaná třída implementována v X++ nebo v .NET.
Je-li obsluha události spuštěna před metodou, má možnost číst a měnit vstupní parametry, post-event handler může číst a měnit návratovou hodnotu. V obou případech je navíc možné pracovat se stavem objektu (pokud jde o instanční metodu).
Jedna metoda může kombinovat pre- a post- události a může obsahovat více než jednu metodu zpracovávající událost daného typu. Takže je možné mít u jedné metody tři handlery spouštěné před vlastní metodou a dva handlery po jejím ukončení. Handlery jsou spouštěné sekvenčně a pořadí spuštění je dáno pořadím uzlů v AOT.
Handlery
Handler lze vytvořit zvolením New > Pre- or post-event handler z kontextové nabídky na třídě. To, co vznikne, je úplně normální metoda, takže ji můžete napsat též ručně, z šablony a podobně.
Handler je veřejná statická metoda s návratovým typem void (práce s návratovou hodnotou probíhá jinak, viz dále). Akceptuje jeden parametr typu XppPrePostArgs nebo má stejné parametry jako obsluhovaná metoda. Použití XppPrePostArgs je komplikovanější a znemožňuje kontrolu typu parametrů při kompilaci, ale zpřístupňuje řadu důležitých vlastností.
Deklarace nerozlišuje mezi pre-event a post-event handlery, takže jeden handler může být použit před i za obsluhovanými metodami. Pochopitelně ne všechny funkce mají smysl v obou kontextech – například nastavení návratové hodnoty nemá v pre-event handleru žádný efekt. Zda je handler volán jako pre- nebo post-event lze zjistit pomocí XppPrePostArgs.getCalledWhen(). (A osobně bych doporučoval dát jasně najevo, že je určitý handler určený jen pro jeden z případů, například pomocí Debug::assert(_args.getCalledWhen() == XppEventHandlerCallerWhen::Post);
.)
Pre-event handler
Pre-event handler v AX2012 představuje metodu, která je volána před obsluhovanou metodou. Je volán po vyhodnocení hlavičky metody (nastavení defaultních hodnot nepovinných parametrů), ale před tělem metody.
Umožňuje číst a měnit parametry metody a pracovat se stavem objektu, například volat parm* metody.
Ukázka: deklarace handlerů
//obsluha metody run() public static void runHandler() //stejné parametry jako run() = žádné public static void runHandler(XppPrePostArgs _args) //obsluha metody run(int _iterace) public static void runHandler(int _iterace) //stejné parametry jako run() public static void runHandler(XppPrePostArgs _args)
Ukázka: Práce s parametry v XppPrePostArgs
public static void runHandler(XppPrePostArgs _args) { //získání hodnoty - dle jména parametru int iterace = _args.getArgs('_iterace'); //získání hodnoty - dle pořadí parametru int iterace = _args.args().valueIndex(1); if (iterace > 100) { //nastavení hodnoty parametru _args.setArg('_iterace', 100); } }
Post-event handler
Post-event handler probíhá po skončení obsluhované metody, ale před vrácením hodnoty a řízení volajícímu kódu. Handler tak má možnost číst návratovou hodnotu (např. pro logování) a případně ji i měnit. Může také pracovat se stavem volajícího objektu (viz ukázku).
public static void validatePostHandler(XppPrePostArgs _args) { SomeTable someTable; //Čtení návratové hodnoty if (_args.getReturnValue()) { //Získání volajícího objektu someTable = _args.getThis(); if (someTable.SomeField == '') { warning("Chybějící hodnota"); //Nastavení návratové hodnoty _args.setReturnValue(false); } } }
Debugging
Do obslužných metod můžete samozřejmě umisťovat breakpointy, ale můžete kód i krokovat a dostat se tak například do post-event handleru pomocí Step Into (F11) na uzavírací závorce obsluhované metody.
Závěr
Nejsem si jist, co byla hlavní motivace pro vytvoření této funkcionality, každopádně nám umožňuje zmenšit závislosti mezi objekty a provádět určité typy změn ve třídách či tabulkách beze změny jejich kódu. A kde není změna v kódu, nemůže nastat ani konflikt v kódu (konflikty na úrovni uzlů v AOT se řeší výrazně snáze).
Události v Dynamics AX 2012 toho nabízí ještě daleko více – pokusím se navázat na tento příspěvek co nejdříve.