Dynamics AX Blog - Axapta 2.5 - Microsoft Dynamics AX (Axapta) - Seite 2

In den letzten Jahren, in denen ich mich fast hauptsächlich mit der Entwicklung im Umfeld von Microsoft Dynamics AX (vormals Axapta) beschäftigt habe, ist das eine oder andere Code-Fragment entstanden, von dem ich mir vorstellen könnte, daß es auch für andere AX-Entwickler ganz nützlich sein könnte. Aber auch Tips und Tricks zu dem mächtigen ERP-System werde ich in dieser Kategorie präsentieren.
RSS-Feed dieser Kategorie
RSS-Feed dieser Version
PageFooter sind nicht immer dort, wo sie sein sollten
04.12.2009Microsoft Dynamics AX (Axapta)
Ich kenne kein einziges AX-Projekt, in dem nicht zumindest einer der Berichte Auftragsbestätigung, Ausgangslieferschein oder Ausgangsrechnung angepasst worden sind. Und deshalb stolpere ich auch immer wieder über das selbe Problem: Man erweitert einen Bericht (Report) um einen PageFooter, der aber nicht auf jeder Seite angedruckt werden soll. |
Arbeiten mit dem aufrufenden Objekt einer Form (Caller)Nachstehende Methode enthält einige Snippets, die in einem Formular verwendet werden können, um in Dynamics AX diverse Funktionen/Methoden des Aufrufenden Objektes aufzurufen. Ändert man element.args() auf z.b. _args und übergibt der Methode diese als Parameter, kann die selbe Logik auch aus einer Klasse heraus verwendet werden. void workWithCallingRecord() { common common; object object; formDataSource formDataSource; formRun formRun; inventDim inventDim; salesTable salesTable; int i; ; // Call method from calling record if( element.args() && element.args().record() ) { common = element.args().record(); if(common.isFormDataSource()) { info(tableId2Name(common.TableId)); if(formDataSourceHasMethod(common.dataSource(), identifierStr("someMethod"))) { object = common.dataSource(); object.someMethod(); } } } // Call method from calling form if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun')) { formRun = element.args().caller(); if(sysFormRun::hasMethod(formRun, identifierStr("someFormMethod"))) { object = formRun; object.someFormMethod(); } } // Get value from calling record if( element.args() && element.args().record() ) { common = element.args().record(); if(common.TableId == tableNum(salesTable)) { info(common.(fieldNum(salesTable, salesId))); } } // Get value from calling datasource (form with multiple datasources) if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun')) { formRun = element.args().caller(); for (i = 0; i <= formRun.dataSourceCount(); i++) { formDataSource = formRun.datasource(i); if (formDataSource && formDataSource.table() == tablenum(inventDim)) // Search for specific table { inventDim = formDataSource.cursor(); break; } } if(inventDim) { info(inventDim.InventLocationId); } } // Change data in calling datasource if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun')) { formRun = element.args().caller(); for (i = 0; i <= formRun.dataSourceCount(); i++) { formDataSource = formRun.datasource(i); if (formDataSource && formDataSource.table() == tablenum(salesTable)) // Search for specific table { salesTable = formDataSource.cursor(); break; } } if(salesTable) { // Update data salesTable.PurchOrderFormNum = "Some value"; salesTable.update(); } } // Refresh calling datasource if( element.args() && element.args().record() ) { common = element.args().record(); if(common.isFormDataSource()) { formDataSource = common.dataSource(); formDataSource.research(true); } } } |
Dynamics AX: Illegal property valueWenn man in Dynamics AX versucht die Eigenschaft AllowDuplicates eines Tabellen-Indexes von No auf Yes zu ändern, kann folgende Fehlermeldung auftreten: Illegal property value In diesem Fall ist vermutlich der betroffene Index als PrimaryIndex oder ClusteredIndex der Tabelle eingetragen. Eigentlich auch logisch :-) |
Dynamics AX: Das RunBaseBatch-Framework
09.08.2008Microsoft Dynamics AX (Axapta)
Man braucht es immer wieder, und genau darum findet Ihr im folgenden eine kurze - und bestimmt auch nicht ganz vollständige - Übersicht, wie dieses RunBaseBatch-Framework benutzt werden kann. Erste Anlaufstelle sollte übrigens in jedem Fall die Klasse Tutorial_RunBaseBatch sein, dort werden die wichtigsten Methoden verwendet und man kann sich so zumindest einen groben Überblick verschaffen, was wie möglich ist. Um eine stapelverarbeitungsfähige Klasse zu schaffen, ist diese in erster Linie von RunBaseBatch abzuleiten. Dadurch stehen eine Reihe von Methoden zur Verfügung, von welchen ich einige versuche im Folgenden zu erklären. |
Dynamics AX: Methode des "Callers" aufrufen
17.06.2008Microsoft Dynamics AX (Axapta)
Immer wieder besteht die Notwendigkeit, ein Formular über ein anderes zu öffnen und aus diesem heraus Methoden des Aufrufers aufzurufen. Einfaches Beispiel: Ich öffne aus der Auftragsmaske (Salestable) irgendein anderes Formular (über einen MenuItemButton) und möchte nun beim Schliessen dieses Formulares eine Methode in der Salestable-Maske aufrufen. Achtung: IntelliSense funtioniert in diesem Fall nicht (außer ich möchte eine Methode aufrufen, die im FormRun-Objekt enthalten ist). if (element.args() && element.args().caller()) { if (element.args().caller().name() == formStr(Salestable)) { element.args().caller().myMethod(); } } |
e-Mail-Validierung in MS Dynamics AX
18.10.2007Microsoft Dynamics AX (Axapta)
Manchmal ist es notwendig, eingegebene E-Mail-Adressen auf deren Syntax hin zu überprüfen. Genau für dieses Zweck habe ich die nachfolgende Methode geschrieben. Schliesslich verfügt MS Dynamics AX erst ab Version 4.0 über eine entsprechende eigene Methode (SysEmailDistributor.validateEmail). static boolean isValidMailAddress(str _mailAddress, str 2 _separator4MultipleAddresses = ";") { // Prüft Mail-Adressen auf ihre Gültigkeit. // Es können auch mehrere Adressen auf einmal geprüft werden, dabei ist der Parameter _separator4MultipleAddresses zu verwenden boolean ret = true; int i = 0; str 1 buchstabe, firstZeichen = '', firstDomainZeichen; int firstAT = 0, firstDot = 0, lastDot = 0; str errorText = ''; int z, x, y; email SubMailAddr; container SubMailAddrContainer, c; container str2conLocal(str _value, str 10 _sep = ',') // str2con von AX30 ist fehlerhaft, wenn der ein Teilstring mit einer { // Zahl beginnt und als Separatir , verwendet wird int length = strlen(_value); int u = 1; int j = strscan(_value, _sep, 1, length); container retContainer; while (j) { retContainer+=(substr(_value, u, j-u)); u = j+1; j = strscan(_value, _sep, u, length); } retContainer+=(substr(_value, u, length-u+1)); return retContainer; } ; if(strLen(_MailAddress) == 0) { return true; } SubMailAddrContainer = str2conLocal(_MailAddress, _separator4MultipleAddresses); for(z=1;z<=ConLen(SubMailAddrContainer);z++){ SubMailAddr = ConPeek(SubMailAddrContainer,z); if(subMailAddr == '') { continue; } // Variablen initieren i=0; firstzeichen=''; firstDomainZeichen=''; lastdot=0; firstDot=0; firstAT=0; buchstabe=''; errorText = StrFmt('Die E-Mail-Adresse "%1" wurde falsch eingegeben', subMailAddr) + '. '; // ###### Start der Prüfung ########### lastDot = strFind(SubMailAddr, '.', strLen(SubMailAddr), -1 * strLen(SubMailAddr)); // @ muß zumindest einmal vorkommen firstAT = StrScan(SubMailAddr, '@', 1, strLen(SubMailAddr)); if(firstAT == 0) { return checkFailed(errorText + 'In der Mail-Adresse muß zumindest ein @-Zeichen vorkommen'); } // @ darf nur einmal vorkommen if(StrScan(SubMailAddr, '@', firstAT + 1, strLen(SubMailAddr)) != 0) { return checkFailed(errorText + 'Das @-Zeichen darf nur einmal vorkommen'); } // . muß zumindest einmal vorkommen firstDot = StrScan(SubMailAddr, '.', 1, strLen(SubMailAddr)); if(firstDot == 0) { return checkFailed(errorText + 'In der Mail-Adresse muß zumindest ein Punkt vorkommen'); } // nach dem @ muß zumindest 1 punkt kommen if(StrScan(SubMailAddr, '.', firstAT, strLen(SubMailAddr)) == 0) { return checkFailed(errorText + 'Nach dem @-Zeichen muss zumindest ein Punkt vorkommen'); } // nach dem letzten punkt darf nur 2 bis 4 zeichen kommen if(StrLen(SubStr(SubMailAddr,lastDot +1,strLen(SubMailAddr))) > 4 || StrLen(SubStr(SubMailAddr,lastDot +1,strLen(SubMailAddr))) < 2) { return checkFailed(errorText + 'Die Domän-Endung muss aus mindestens 2 und maximal 4 Zeichen bestehen'); } // Sub-Domänen müssen zumindest 2 Stellen gross sein und müssen mit A-Z oder 0-9 anfangen c = str2conLocal(SubStr(SubMailAddr, firstAT + 1, strLen(SubMailAddr)), "."); for (x=1; x<=conLen(c); x++) { firstDomainZeichen = SubStr(conPeek(c,x), 1,1); if( !( ( char2num(firstDomainZeichen,1) >= 97 && char2num(firstDomainZeichen,1) <= 122 ) || ( char2num(firstDomainZeichen,1) >= 48 && char2num(firstDomainZeichen,1) <= 57 ) || ( char2num(firstDomainZeichen,1) >= 65 && char2num(firstDomainZeichen,1) <= 90 ) ) ) { return checkFailed(errorText + 'Jede Subdomäne muss mit einem Buchstaben oder einer Zahl beginnen'); } if(strLen(conPeek(c,x)) < 2) { return checkFailed(errorText + 'Jede Subdomöne muss aus zumindest 2 Zeichen bestehen'); } // Subdomänen dürfen nur aus A-Z 0-9 oder - bestehen for(y=1;y<=strLen(conPeek(c,x));y++) { buchstabe = SubStr(conPeek(c,x),y,1); if( !(char2num(buchstabe,1) == 45 || // - ( char2num(buchstabe,1) >= 97 && char2num(buchstabe,1) <= 122 ) || ( char2num(buchstabe,1) >= 48 && char2num(buchstabe,1) <= 57 ) || ( char2num(buchstabe,1) >= 65 && char2num(buchstabe,1) <= 90 ) ) ) { return checkFailed(errorText + strFmt('In der Subdomäne "%1" ist das Zeichen "%2" nicht erlaubt!',conPeek(c,x),buchstabe)); } } } // Text vor dem @ (durch Punkte getrennt) muss mindestens 1 Stelle lang sein c = ConNull(); c = str2conLocal(SubStr(SubMailAddr, 1, firstAT-1), "."); for (x=1; x<=conLen(c); x++) { if(strLen(conPeek(c,x)) < 1) { return checkFailed(errorText + 'Der Text vor dem @-Zeichen ist ungültig'); } } // muß mit a-z oder A-Z oder 0-9 beginnen firstZeichen = SubStr(SubMailAddr, 1,1); if( !(( char2num(firstZeichen,1) >= 97 && char2num(firstZeichen,1) <= 122 ) || ( char2num(firstZeichen,1) >= 48 && char2num(firstZeichen,1) <= 57 ) || ( char2num(firstZeichen,1) >= 65 && char2num(firstZeichen,1) <= 90 )) ) { return checkFailed(errorText + 'Die Mailadresse muss mit einem Buchstaben oder einer Zahl beginnen'); } // Gültiges Zeichen i = 0; for(i=1;i<=StrLen(SubMailAddr);i++) { buchstabe = SubStr(SubMailAddr,i,1); if( !(char2num(buchstabe,1) == 46 || // . char2num(buchstabe,1) == 45 || // - char2num(buchstabe,1) == 95 || // _ char2num(buchstabe,1) == 64 || // @ char2num(buchstabe,1) == 228 || // ä char2num(buchstabe,1) == 252 || // ü char2num(buchstabe,1) == 246 || // ö char2num(buchstabe,1) == 196 || // Ä char2num(buchstabe,1) == 220 || // Ü char2num(buchstabe,1) == 214 || // Ö ( char2num(buchstabe,1) >= 97 && char2num(buchstabe,1) <= 122 ) || ( char2num(buchstabe,1) >= 48 && char2num(buchstabe,1) <= 57 ) || ( char2num(buchstabe,1) >= 65 && char2num(buchstabe,1) <= 90 ) ) ) { return checkFailed(errorText + strFmt('Ungültiges Zeichen "%1" in der Mail-Adresse', buchstabe)); } } } return true; } Obiger Code sollte in allen AX-Versionen funktionieren. Verwendung natürlich auf eigene Gefahr. |
|
|
|
|
|
|
Schon einmal einen Base Enum in Dynamics AX erstellt? Oder einen bestehenden erweitert?
Ja?! Dabei auch auf das folgende geachtet?
.) Das erste Element eines Base Enums sollte den Wert 0 aufweisen und dieser sollte "Undefiniert", "Kein", "Unbekannt" oder ähnlichem entsprechen. Vor allem wenn man den Base Enum später in Tabellen verwenden möchte, die bereits Daten enthalten.
Selbst wenn man davon ausgehen kann, daß man einen solchen undefinierten Zustand nicht benötigt, sollte man die 0 reserviert halten, sprich der erste "echte" Wert des Base Enums sollte 1 entsprechen.