úterý 28. července 2009
SysCompareCreateProject
Dnes jsem potřeboval vypsat objekty existující v jedné vrstvě a změněné v jiné vrstvě. Nejdřív mě napadl upgrade projekt, ale pak jsem objevil třídu SysCompareCreateProject. Zadám vrstvy, jméno privátního projektu a jedem…
Jenže do projektu se mi dostaly i ty objekty, které ve vyšší vrstvě prostě chyběly, a to jsem nechtěl. Pokusně jsem upravil podmínku v compareNodes() a vše bylo OK. Před zásahem do dialogu (aby bylo možné chování měnit) jsem se ještě podíval do AX2009 (tohle bylo na 3.0) a co myslíte? Jasně, přesně tohle tam už je implementováno. :-)
neděle 19. července 2009
Reflexe - vytvoření objektu, volání metod
Původně jsem se chtěl vrátit k Team Foundation Serveru, ale času se nějak nedostává a plány se odsouvají...
Takže raději zpátky k tématu reflexe. V poslední době jsem níže uvedené informace vyvsvětloval postupně několika lidem, tak bude asi vhodné to sepsat.
Podívejme se na případ, kdy máme jméno (nebo ID) třídy a chceme vytvořit instanci.
ClassName className = 'SalesFormLetter_Invoice';
SysDictClass dictClass = new SysDictClass(className2Id(className));
FormLetter formLetter;
;
formLetter = dictClass.makeObject(true);
Jméno jsem převedl na ID, vytvořil instanci SysDictClass a zavolal metodu makeObject(). Té lze předat parametry, které očekává konstruktor. Je zajímavé, že nedojde k run-time chybě ani když vynechám povinný parametr (AX přiřadí parametru default hodnotu). Vtipně provádí validaci SysDictClass.allowMakeObject(). :-)
Teď můžeme zavolat metodu objektu FormLetter. Na tom nic není. Ale co když neznám typ objektu? Mohu například zjistit, zda třída implementuje nějaké rozhraní a přetypovat na něj.
if (dictClass.isImplementing(classNum(SysRunable)))
{
sysRunable = dictClass.makeObject();
sysRunable.run();
}
Obdobně zjistím, zda je potomkem nějaké třídy.
if (dictClass.isExtending(classNum(RunBaseBatch)))
Nebo prostě zkusím, zda má objekt nějakou konkrétní metodu:
IdentifierName methodName = 'xml';
SysDictClass dictClass = new SysDictClass(classNum(Query));
Object object;
;
object = dictClass.makeObject();
if (dictClass.hasObjectMethod(methodName))
{
info(dictClass.callObject(methodName, object, 10));
}
Metoda callObject() tedy očekává název metody, instanci objektu, jehož metoda se má volat, a případné parametry metody.
Obdobně lze volat i statické metody. Jedno z možných použití je samozřejmě i vytvoření instance:
SysDictClass dictClass = new SysDictClass(classNum(InventItemType));
Object object;
;
object = dictClass.callStatic('construct', ItemType::Service);
U tabulek je to pak velmi podobné, jen místo makeObject() se použije makeRecord():
SysDictTable dictTable = new SysDictTable(tableNum(LedgerJournalTrans));
Common common;
;
common = dictTable.makeRecord();
dictTable.callObject('initFromCustTable', common, CustTable::find('1'));
U tabulek nás ale většinou zajímá jestě jedna věc a tou věcí jsou datová pole. Tam přijde ke slovu trochu neobvyklá syntaxe tabulka.(číslo pole). Například:
InventTable inventTable = InventTable::find('1');
SalesLine salesLine = SalesLine::findInventTransId('12345', true);
Common table1 = inventTable;
Common table2 = salesLine;
FieldId fieldId1 = fieldNum(InventTable, ItemId);
FieldId fieldId2 = fieldNum(SalesLine, ItemId);
;
table1.(fieldId1) = table2.(fieldId2);
Poslední příklad ukazuje, jak získat hodnotu na základě jména pole:
SysDictTable dictTable;
Common common;
FieldId fieldId;
;
dictTable = new SysDictTable(common.TableId);
fieldId = dictTable.fieldName2Id('Name');
if (fieldId)
{
info(common.(fieldId));
}
Užitečný odkaz:
MSDN: Intrinsic Functions
sobota 18. července 2009
SysMultiTableLookup
Tento týden jsem potřeboval vytvořit lookup s poli z různých tabulek. Věděl jsem o existenci třídy SysMultiTableLookup, ale nějak jsem ji dříve nepotřeboval. A teď tedy přišel čas, abych se na ni podíval.
Tuto třídu vytvořil Vanya Kashperuk (blog) s cíle rozšířit funkcionalitu široce používané třídy SysTableLookup. SysMultiTableLookup přináší možnost zobrazovat pole z více tabulek, používat display metody, agregační funkce nebo zadat jiný než standardní popisek pole. Vše, co jsem vyzkoušel, funguje velmi dobře. Skvělá práce!
Třídu a formulář s příklady lze stáhnout zde.
neděle 12. července 2009
Reflexe - úvod
Reflexe (reflection) umožňuje pracovat se strukturou programu samotného. Když například Unit Testing Framework spouští všechny metody začínající "test", využívá k tomu reflexi. Hrátky s reflexí jsou zábavné a zároveň umožní tvořit velmi zobecněná řešení některých problémů, takže ji určitě neignorujte. :-)
Obecně bych rozdělil využití reflexe v Axaptě do dvou hlavních oblastí:
1. Analýza aplikace - například:
- vyhledání tříd implementujících dané rozhraní (Které RunBaseBatch třídy se mění aktuálním releasem?)
- výpis polí tabulky pro uživatelský výběr (AIF, DEV_SysTableBrowser)
- generátory kódu (metoda find() na základě primárního indexu)
- atd.
- volání metod na základě dat (Např. volám konkrétní metodu všech tříd, jejichž názvy jsem uložil do tabulky. To mi umožní měnit aplikační logiku dle aktuálních požadavků bez potřeby zásahu do kódu.)
- provedení určité akce se všemi poli v tabulce, nebo třeba s poli určitého datové typu (validace)
- atd.
- TreeNode - představuje práci s AOT. Umožňuje procházet AOT, spouštět objekty, vytvářet, exportovat, pracovat s vrstvami atd. Základem je třída TreeNode, resp. její rozšíření SysTreeNode.
- Dictionary - pracuje jen s datovým slovníkem (EDT, tabulky, třídy; ne třeba formuláře), ale objektům "rozumí" lépe než TreeNode. Pracuje s dědičností, přístupovými modifikátory (např. private), databází atd. Využívá systémové třídy Dict* a aplikační třídy SysDict*, v kterých jsou mnohá užitečná rozšíření.
- křížové reference (pokud jsou aktuální, samozřejmě)
- UtilElements a další systémové tabulky
- polymorfismus (jinak řečeno - řešení vhodným objektovým návrhem)
Dictionary dictionary = new Dictionary();
DictClass dictClass;
ClassId classId;
;
classId = dictionary.classNext(0);
while (classId)
{
dictClass = dictionary.classObject(classId);
info(strFmt(
"Třída %1 - instančních metod: %2",
dictClass.name(),
dictClass.objectMethodCnt()));
classId = dictionary.classNext(classId);
}
Ukázka 2 - TreeNode
TreeNode formsNode = TreeNode::findNode(@'\Forms\'); //cesta v AOT
TreeNodeIterator iterator;
TreeNode formNode;
;
iterator = formsNode.AOTiterator();
formNode = iterator.next();
while (formNode)
{
info(strFmt(
"Formulář %1 - datových zdrojů: %2",
formNode.AOTname(),
formNode.AOTfindChild('Data Sources').AOTchildNodeCount()));
formNode = iterator.next();
}
Videa
Dnes uvedu pár tipů na videa týkající se Axapty. Některé věci je prostě dobré vidět v chodu.
Hlavním zdrojem je Channel 9 na MSDN. Dají se tam najít i např. rozhorvory s tvůrci, ale já jsem vybral linky na několik screencastů:
Dynamics AX 2009 AIF Web Services
Dynamics AX 4.0 - Unit Testing
Exception handling in X++
Dynamics AX 4.0 - 3-tier Development
Samozřejmě se dá něco najít i na známém YouTube (BTW není nad český překlad TyTrubko ;)), například:
Dynamics AX Item Approval Workflow
Setting Up Outlook Sychronization in Dynamics AX 2009
TabaxLite & Microsoft Dynamics Ax (TabaxLite je verze Tabaxu určená pro koncové uživatele)
A nakonec zmíním tutoriály na MSDN:
“How Do I” Videos — Dynamics AX
PS: Celkem nedávno rozjel český Microsoft portál MSTV - přímo k Dynamics tam sice nic není, ale zato spousta zajímavostí ohledně .NETu...
středa 24. června 2009
Vyšla kniha Inside Microsoft Dynamics AX 2009
Knížka Inside Microsoft Dynamics AX 2009 je v prodeji, samozřejmě v angličtině. (link)
úterý 9. června 2009
Tabax
Prostředí Dynamics AX má k dokonalosti v mnoha ohledech daleko a některé úkoly jsou tak zbytečně komplikované. V tu chvíli přichází ke slovu programátor, jehož základní vlastností je lenost :), a pro zjednodušení práce si napíše utilitku. Vývojáři Dynamics AX nejsou výjimkou a mnozí si své nápady nenechávají pro sebe - díky tomu lze na internetu nalézt řadu zajímavých nástrojů. Třeba Tabax.
Největším přínosem Tabaxu je umisťování oken na panel záložek, takže nemusíte složitě hledat schovaná okna. V AX2009 se sice některé formuláře otevírají mimo hlavní okno, ale přesto záložky Tabaxu rozhodně využijete.
Dále Tabax nabízí nástrojovou lištu, kde sice nenajdete mnoho nového, ale např. možnost jednou kliknout pro otevření aktivního formuláře v AOT ušetří spoustu neproduktivního času.
Pro názornost screenshoty z AX3 a AX2009:
Stručný popis funkce tlačítek (AX2009):





Edit current form
Edit current field
Table browser
Refresh AOD
xReferences - usedBy
Application Hierarchy Tree
Copy
Open Application Object
Add-ins
Compare
Import
Search
Label Search
About

Pause
Preferences
Close

Stručný popis funkce tlačítek (AX2009):





- Slouží k rozmisťování oken.
Edit current form- Otevře aktivní formulář v AOT (jinak řečeno, přejdu z uživatelského pohledu na formulář do jeho editace).
Edit current field- Otevře aktivní formulářový prvek v AOT. Funkce je sice určeno pro pole, ale s úspěchem lze aplikovat i třeba na MenuItemButton.
- Ctrl+Click - Vypíše do infologu podrobné informace o aktivním poli - např. jméno prvku, jméno pole (popř. metody), použitý datový typ, jeho rozsah atd.
- Ctrl+Shift+Click - Otevře v AOT použitý datový typ a zobrazí jeho vlastnosti (Properties).
Table browser- Otevře tabulku v prohlížeči tabulek (form SysTableBrowser). Funkci můžete použít přímo z formuláře (otevře se tabulka, do níž patří aktivní pole), ale také v podstatě kdekoli v AOT, kde narazíte na tabulku (např. v definici query na tiskové sestavě).
- Shift+Click - Zobrazí seznam tabulek, které jsou na formuláři použity. Zvolenou tabulku pak zobrazí v prohlížeči tabulek. Pokud je k dispozici pouze jediná tabulka, je zobrazena rovnou.
- Ctrl+Click - Funguje obdobně jako Shift, ale zvolenou tabulku otevře v AOT.
- Ctrl+Shift+Click - Zobrazí SQL dotaz použitý k vygenerování aktivního datového zdroje formuláře. Úžasně užitečná funkce pro ladění složitých filtrů, dynamicky připopojovaných datových zdrojů apod.
Refresh AOD- Vymaže nacachované informace o aplikačních objektech (na klientu).
xReferences - usedBy
- Zobrazí křížové reference, tedy informaci, kde všude je zvolený objekt používán. Samozřejmě to vyžaduje aktuální křížové reference…
Application Hierarchy Tree
- Zobrazí Strom aplikační hierarchie pro aktivní datový typ nebo třídu. Funguje to i pro systémové objekty, takže se můžete třeba podívat, jaké potomky má třída TreeNode.
Copy
- Zkopíruje do schránky název vybraného objektu (objektů), nebo, v případě formuláře, AxPath odkaz na aktivní záznam.
- Ctrl+Click - Zkopíruje AOT cestu (např. \Classes\RunBase\run).
- Ctrl+Shift+Click - Zkopíruje AxPath odkaz. AxPath vydá na samostatný příspěvěk, ale v zásadě jde o protokol pro odkazování do AX (např. na konkrétní záznam v konkrétním formuláři), takže je pak možné jednoduše kliknout na odkaz třeba z e-mailu a v AX se otevře cíl odkazu. Více v angličtině zde.
Open Application Object
- Otevře aplikační objekt v novém okně. Je to užitečné, jsem-li na nějaké části aplikačního objektu (např. na metodě v editoru) a chci otevřít celý objekt v AOT.
- V případě otevřeného formuláře otevře v novém okně objekt, který daný formulář vyvolal (caller). To je většinou jiný formulář nebo třída.
Add-ins
- Otevře menu Add-ins. Víc od toho nečekejte. :-)
Compare
- Porovná dvě verze objektu (verze z různých vrstev nebo ve smyslu verzí v repository), případně dva objekty mezi sebou. Bohužel na mé instalaci na AX2009 to nefunguje a zatím nevím proč. :-(
Import
- Zobrazí dialog pro import .xpo.
Search
- Zobrazí dialog pro vyhledávání v AOT pro vybrané objekty.
Label Search
- Zobrazí Editor popisků.
- AOT cestu (třeba \Classes\Info) - otevře objekt v AOT; metodu přímo v editoru.
- Výraz začínající otazníkem (např. ?74 MOD 17 nebo ?tableId2Name(177)) - vyhodnotí výraz a výsledek vypíše do infologu.
- Příkaz začínající vykřičníkem (např. !beep();) - provede příkaz.
- Ostatní - vyhledá text na Googlu. Je tam nastavené hledání AxSearch, které mi ale nepřijde příliš užitečné.
About
- Verze, odkaz na domovskou stránku, text licence.

Pause
- Pozastaví úlohy Tabaxu běžící na pozadí. Nevím, co přesně dělají, ale ve výpisu profileru opravdu nehezky překáží. Toto tlačítko problém řeší.
Preferences
- Obsahuje několik nastavení, např. maximální velikost záložky.
Close
- Ukončí Tabax.
// if shift is pressed skip running tabax if(!WinAPI::isShiftButtonDown()) { // check for user ID if(curUserId()=='bmi') // <- change to your loginname { // actually run tabax TreeNode::findNode(@'\Forms\'+formStr(Tabax)).AOTrun(); } }Nebo, pokud chcete nastavovat spouštění pro různé uživatele či skupiny uživatelů, můžete zkusit <reklama>můj StartupTool</reklama>. Odkazy: Axaptapedia: Tabax Axaptapedia: Tabax Plugin API Axaptapedia: AxPath Max Belugin: New AxPath plugin
Přihlásit se k odběru:
Příspěvky (Atom)