Na velikosti záleží

X++ normálně nerozlišuje velikost písmen – můžete zavolat warning(„x“) nebo WaRnInG(„x“) a oboje udělá to samé (ačkoli vaši kolegové nemusí být tak benevolentní jako kompilátor X++). Nicméně to samé naplatí pro .NET Interop z X++ – můžete sice použít například System.Math::Cos(0), ale pokud zkusíte zavolat System.Math::cos(0), dostanete kompilační chybu.

Existují dokonce případy, kdy změna velikosti písma zapříčiní volání jiné metody. Podívejte se na následující kus kódu – způsobí .NET výjimku, odchytne ji, převede na řetězec a odešle do infologu:

try
{
    System.IO.File::Open('neexistující soubor', System.IO.FileMode::Open);
}
catch (Exception::CLRError)
{
    error(CLRInterop::getLastException().ToString());
}

Výstup by měl být něco jako: „System.Reflection.TargetInvocationException: Exception has been thrown by the target of invocation. —> System.IO.FileNotFoundException: Could not find file ‚C:\Windows\system32\neexistující soubor.‘ (…)“ (Poznámka: nevím, co přesně dostanete v systému s češtinou.)

Nyní změňte ToString() na tostring(). Výstup bude „Class CLRObject“.

Co se stalo? To, co dostaneme z CLRInterop::getLastException() je instance (X++) třídy CLRObject, která reprezentuje .NET objekt (v tomto případě FileNotFoundException). Když zavoláme metodu ToString(), AX rozpozná, že FileNotFoundException takovou metodu obsahuje a zavolá ji. Ale pokud zavoláte tostring(), AX nemůže použít metodu na FileNotFoundException kvůli různé velikosti písmen. Ale je zde metoda toString() na samotné třídě CLRObject (zděděná z třídy Object), která může být zavolána bez potíží. Tudíž zde nejde o jednu metodu vracející různé výsledky, jsou to metody na úplně jiných objektech.

Můžete to být trochu matoucí, ale dává to smysl.

Řádky pro více hlaviček

Cílem dnešního cvičení je vytvoření formuláře s dvěma gridy (obsahující hlavičky a odpovídající řádky). Trik je v tom, že pokud vyberete více hlaviček, formulář zobrazí řádky pro všechny.

Následující formulář využívá prodejní objednávky. Všimněte si, že vybrané objednávky mají čísla 1, 3 a 4 a zobrazené řádky také patří k objednávkám 1, 3 a 4:

Form

Vytvořil jsem dvě implementace: jednu pro AX2012 a jednu pro AX2009. Nejsou úplně stejné – nejprve popíšu AX2012 a pak zmíním změny nutné pro AX2009. Link na stažení obou verzí najdete na konci.

Formulář má dva datové zdroje (SalesTable a SalesLine), které spolu nejsou spojeny. Fitrování a spouštění dotazu nezajišťuje AX, je spouštěno explicitně z metody selectionChanged() na datovém zdroji SalesTable.

Pro každou zvolenou hlavičku je přidán nový filtr do datového zdroje SalesLine:

Ranges

Mohli byste použít jen jeden filtr a vytvořit jednu dlouhou hodnotu spojením čísel objednávek oddělených čárkou (např. „000001, 000002“), nicméně to má jeden velký problém: podporovaná délka hodnoty filtru není neomezená (použitím dostatečně dlouhé hodnoty se mi dokonce podařilo sestřelit klienta AX2012). Mít více krátkých hodnot je také výhodné při zobrazování fitrů v gridu (jako na předchozím obrázku).

Implementace je docela přímočará, neměli byste v ní jinak tápat:

public class FormRun extends ObjectRun
{
    MultiSelectionHelper headerSelection;
    QueryBuildDataSource lineQueryDs;
}
 
public void init()
{
    super();
 
    // Initalizuj MultiSelectionHelper pro pozdější použití
    headerSelection = MultiSelectionHelper::construct();
    headerSelection.parmDatasource(salesTable_ds);
 
    // Pro pohodlný přístup k instanci QueryBuildDataSource pro řádky
    // (v AX2012 byste mohli použít salesLine_ds.queryBuildDataSource())
    lineQueryDs = salesLine_ds.query().dataSourceNo(1);
}
 
public void selectionChanged() // Datový zdroj SalesTable
{
    super();
    SalesLine_ds.executeQuery();
}
 
public void executeQuery() // Datový zdroj SalesLine
{
    lineQueryDs.clearRanges();
    this.filterBySelectedHeaders();
 
    super();
}
 
void filterBySelectedHeaders() // Datový zdroj SalesLine
{
    SalesTable st = headerSelection.getFirst();
 
    while (st.RecId)
    {
        // Přidej jeden filtr pro každé vybrané SalesId
        lineQueryDs.addRange(fieldNum(SalesLine, SalesId)).value(queryValue(st.SalesId));
        st = headerSelection.getNext();
    }
}

V AX2009 nemáme metodu selectionChanged(), takže jsem zkombinoval metodu markChanged() a „delayed link“ mezi datovými zdroji, který při změně hlavičky volá executeQuery() pro řádky. Jen jsem musel odebrat dynamický odkaz (dynamic link), jinak by AX ukázala řádky jen pro jednu hlavičku.

Obě verze můžete stáhnout zde: LinesForMultipleHeaders.zip.

Tisk reportu z kódu v AX2012

Jak vytisknout report z X++ a změnit nastavení tisku v AX2012?

Mám pro vás konkrétní příklad – měl by vám dát dobrou představu jak na to, i pokud je váš případ je trochu jiný.

SrsReportRunController          controller = new SrsReportRunController();
SysUserLicenseCountRDPContract  rdpContract = new SysUserLicenseCountRDPContract();
SRSPrintDestinationSettings     settings;
 
// Určete, jaký report and design reportu se má použít
controller.parmReportName(ssrsReportStr(SysUserLicenseCountReport, Report));
// Použijte mód vykonávání vyhovující vaší situaci
controller.parmExecutionMode(SysOperationExecutionMode::ScheduledBatch);
// Potlačte dialog
controller.parmShowDialog(false);
 
// Explicitně určete všechny vyžadované parametry
rdpContract.parmReportStateDate(systemDateGet());
controller.parmReportContract().parmRdpContract(rdpContract);
 
// Dle potřeby změňte nastavení tisku
settings = controller.parmReportContract().parmPrintSettings();
settings.printMediumType(SRSPrintMediumType::File);
settings.fileFormat(SRSReportFileFormat::Excel);
settings.fileName(@'\\share\UserLicenseCount.xlsx');
 
// Spusťte report
controller.startOperation();

Microsoft Virtual Academy Jump Starts

Microsoft Virtual Academy nabízí v příštích dvou týdnech úžasný počet Jump Start lekcí:

Naštěstí se to bude nahrávat, protože budu mít štěstí, když se stihnu podívat alespoň na něco.

AxBuild.exe

Dnes chci jen krátce upozornit na něco, co jste možná minuli.

Microsoft uvolnil malou konzolovou aplikace pro Dynamics AX R2 CU 7 nazvanou AxBuild. Je schopna kompilovat X++ kód přímo na AOS and dělat to v několika vláknech najednou, což má obrovský vliv na výkon. Microsoft dosáhl dokonce 92% (!) zlepšení času kompilace (v pečlivě sestaveném prostředí).

Další výhodou je, že bude snažší získat odezvu z běžící kompilace (to je problém zvlášťe pro kompilace spouštěné automatizovanými skripty). Bohužel AxBuild nepokrývá kompilaci do CIL, ale toho se snad časem také dočkáme.

Neměl jsem zatím příležitost si a AxBuilem pohrát, ale Tommy Skaue už ano, takže se můžete podívat na jeho článek You got to love AXBuild Compiler Tool.