Monday 18 June 2012

Problem Solving Techniques in Ax


Sometimes, when developing, AX doesn’t work as expected, or behaves weird.
Here are some of the things you can try if you run out of ideas, roughly in the order I do:

Try again
You probably already did, but make sure you can reproduce the problem. If it only occurred once, it’s not a problem.

Check your code again
Check your code carefully for errors, and maybe ask a colleague’s opinion.

Compile
Your project might contain compile errors, so compile it to be sure.

Close the debugger
Sometimes, when the debugger is active, AX will keep executing ‘old’ code. Close the debugger to make sure the latest code is executing.

Compile forward
When you have modified a class that is inherited by other classes, you might want to compile forward this class.

Synchronize data dictionary
You may have made changes to application objects that haven’t been synchronized with the database. Open the AOT, right click on the Data Dictionary node and choose Synchronize.

Restart AX client
Simple as that, close the AX client and start it again.

Reset usage data
Go to options screen (AX button > Extra > Options) and click the Usage Data button. Click reset to remove this data.

Check the application event log for clues
Open the event viewer on the AOS to see if the AOS service has logged something in it. Messages here can help you a great deal. You can also check the event log on the database server or your client pc.

Google it
If you receive an error, just copy and paste it in Google. Most likely you are not the only one having that problem.

Check your client version
Check your AX client version. You might for example be connecting to a SP1 application with an SP0 client. You can check this in the about screen: AX button > Help > About. The kernel version indicates the client version, below that is the application version.

Refresh AOD, Dictionary and Data
You can flush cashed information using three option in the Tools > Development tools menu: refresh AOD, refresh Dictionary and refresh Data. This can be useful when you just imported an xpo file, or when you are developing for the enterprise portal.

Delete AUC file
The application Unicode object cache file, if there is one, is located at C:\Documents and Settings\[USERNAME]\Local Settings\Application Data for xp, or C:\Users\USERNAME\AppData\Local for vista. Delete this file while the AX client is closed.

Check if other users are having the same problem
Knowing whether you are the only one that’s having that problem or if it’s a general problem is a big step towards solving the problem. For example, if you alone have the problem, restarting the AOS probably won’t solve it, but removing usage data might.

Check security settings
When only some users have a problem, big changes are that it has something to do with security settings. Security can be set up from Administration > Setup > Security, on the Permissions tab.

Check configuration key setup
Some features of AX won’t work if a configuration key is disabled, be aware of this.

Full compile
Open the AOT, right click the AOT node and select compile.

Restart AOS
Sometimes restarting the AOS solves your problem just fine. If you can, it’s worth the try as this doesn’t take long.

Remove .aoi file
When the AOS is stopped, you can delete the .aoi file from the application files. This file will be rebuilt when the AOS starts.


You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

ShortCut Keys for Ms Dynamics Ax




Command
Dynamics AX 2012
Dynamics AX 2009
Dynamics AX 4.0
Open the AOT
CTRL+D
CTRL+D
CTRL+D
Open a new Development Workspace
CTRL+SHIFT+W
                 
                   -
Open a new Application Workspace
CTRL+W


Insert a Breakpoint
F9
F9
F9
Toggle Breakpoints
CTRL+F9
CTRL+F9
CTRL+F9
Remove all Breakpoints
CTRL+SHIFT+F9
CTRL+SHIFT+F9
CTRL+SHIFT+F9
Execute
F5
F5
F5
Compile
F7
F7
F7
Comment Selected Code
CTRL+E, C
CTRL+E, C
CTRL+E, C
Uncomment Selected Code
CTRL+E, U
CTRL+E, U
CTRL+E, U
Convert to lowercase
CTRL+SHIFT+U
CTRL+SHIFT+U
CTRL+SHIFT+U
Convert to Uppercase
CTRL+U
CTRL+U
CTRL+U
Display all methods and properties for a class
CTRL+SPACEBAR
CTRL+SPACEBAR
CTRL+SPACEBAR
Save all
CTRL+SHIFT+S
CTRL+SHIFT+S
CTRL+SHIFT+S
Select all application objects in a node
CTRL+A
CTRL+A
CTRL+A
Cancel the selection of an additional item
CTRL+SPACEBAR
CTRL+SPACEBAR
CTRL+SPACEBAR
Open the Properties sheet
ALT+ENTER
ALT+ENTER
ALT+ENTER
Open the Import dialog box
CTRL+SHIFT+I
CTRL+SHIFT+I
CTRL+SHIFT+I
Open Help in AOT
F1
F1
F1


The following shortcut keys have changed since Microsoft Dynamics AX 2009:

Old shortcut key
Command
New shortcut key
CTRL+TAB
CTRL+SHIFT+TAB
Go to next (method) TAB
CTRL+M
CTRL+SHIFT+M
CTRL+F4
ESC
Close editor
CTRL+F4
CTRL+SHIFT+Spacebar
Lookup definition
F12
CTRL+L
Delete line
CTRL+X (with cursor in line, no selection)
ALT+O
Select area/column/block
ALT+MOUSE SELECT
ALT+U
Cancel selection
ESC

 Dynamics AX 2012 (Windows and Menus Shortcuts)
To do this
Press
Display the Navigation Pane if it is collapsed.
ALT+F1
Display the View menu.
ALT+V
Display the Windows menu.
ALT+W
Display the Help menu.
ALT+H
Turn the auto-hide mode for the Navigation Pane on an off.
SHIFT+ALT+F1
Move between modules.
CTRL+TAB
Move the cursor to the address bar.
F11
Use the Back function on the address bar.
ALT+LEFT ARROW
Use the Forward function on the address bar.
ALT+RIGHT ARROW

  Commonly used keys for Data Entry
To do this
Press
Paste contents from your clipboard into the current field.
CTRL+V
Enter the session date in a date field.
D+TAB
For a date time field, press D+TAB, enter a time and then press TAB again.
Enter the current date in a date field.
T+TAB
For a date time field, press T+TAB, enter a time and then press TAB again.
Enter a date from the current month in a date field.
[Day]+TAB
For example, if you enter 12+TAB, the full date for the twelfth of the current month will be displayed.
Enter a date from the current year in a date field.
[MonthDay]+TAB
For example, if you enter 0325+TAB, the full date for March 25 of the current year will be displayed.
Calculate an amount in an amount field.
[Equation]+TAB
For example, if you enter 4*16+TAB, 64 will be displayed in the field.



You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

Friday 8 June 2012

Get active window handle


static public HWND getActiveWhd()
{
    HWND                  AxClient, AxChild;
    ;

    AxClient = WinApi::findWindowEx(infolog.hWnd(), 0, "MDIClient", "");
    AxChild = WinApi::findWindowEx(AxClient, nullvalue(AxChild), "", ""); 
    return AxChild;
}


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

Write down the record


To write down the record, which have been just created and does not have modifications use data source method ForceWrite. This method can be used to mark the record as it is changed, and thereby making it a candidate for write, regardless of any changes made to the record. It is valid to call the methods after super in formDataSource::Create(). However, it is not valid in formDataSource::initvalue().


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

Update assembly configuration file on the fly (from code)


The following code could be used to update the DLL configuration file from the code. It could be useful for example when User changes some parameter in Dynamics AX and .NET assemble should use other instance of external application.

//_webReferenceName - the name of webReference (AOT\References)
//_endPoint - the new address
server static void updateAppConfig(str _webReferenceName, str _endPoint)
{
#define.Ax32Serv('Ax32Serv.config')
#define.endPointTag('endpoint')
#define.addressAttribute('address')

SysReference sysReference;
FilePath serverConfigFile;
Microsoft.Dynamics.IntegrationFramework.WebService.AppDomainCache appDomainCache;
XMLDocument xmlDocument;
XMLNodeList xmlNodeList;
XmlElement xmlElement;
;
//Create SysReference object
new InteropPermission(InteropKind::ClrInterop).assert();
sysReference = SysReference::newFromReferenceName(_webReferenceName);
if (sysReference == null)
{
throw error(strfmt("Referenct '%1' was not found", _webReferenceName));
}
CodeAccessPermission::revertAssert();
//Configure
serverConfigFile = xinfo::directory(DirectoryType::Bin) + #Ax32Serv;
new FileIOPermission(serverConfigFile, SysDataExpImp::readWrite2Mode(ReadWrite::read)).assert();
xmlDocument = new XMLDocument();
xmlDocument.load(serverConfigFile);
xmlNodeList = xmlDocument.getElementsByTagName(#endPointTag);
xmlElement = xmlNodeList.nextNode();
while (xmlElement)
{
xmlElement.setAttribute(#addressAttribute, _endPoint);
xmlElement = xmlNodeList.nextNode();
}
CodeAccessPermission::revertAssert();
//BP Deviation documented
new FileIOPermission(serverConfigFile, SysDataExpImp::readWrite2Mode(ReadWrite::Write)).assert();
xmlDocument.save(serverConfigFile);
CodeAccessPermission::revertAssert();
//Reset application cashe - update end point adress
new InteropPermission(InteropKind::ClrInterop).assert();
appDomainCache = Microsoft.Dynamics.IntegrationFramework.WebService.AppDomainCache::get_Instance();
if (appDomainCache)
{
appDomainCache.Remove('LaserNet');
}
CodeAccessPermission::revertAssert();
}


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

Some issues during changing index uniqueness


Some times we need to create a new unique index or alter existing one, but table may already contain duplicate data for this index and our changes could not be applied until data in table fixed to support uniqueness. We could do it by deleting records in the table but due to huge number of companies in environment it could be time consuming. To save your time you could use following job:
static void Job3(Args _args)
{
    MyTable myTable;
    DataArea da;
    int cnt;
    ;
    ttsbegin;
    while select da
    {
        cnt = 1;
        changecompany(da.Id)
        {
            myTable = null;
            while select forupdate myTable
            {
                cnt++;
                myTable.FieldForUniqueness = int2str( cnt );
                myTable.update();
            }
        }
    }
    ttscommit;
}
Another way to solve this problem is to make following steps:
  1. Try to synchronize your table
  2. You get an error saying that there are duplicates
  3. Rright away you go to Administration > Periodic > SQL Administration form.
  4. Select your table in the list and run Table actions > Check/Synchronize command.
  5. In appeared form enable “Check Allow duplicated’” and run.
  6. You will get a list of conflicting records to kill.

Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian   

Select statement patterns


This article contains descriptions of select statement patterns that can be used in the Microsoft Dynamics AX (Axapta).
The list of select statement patterns provided is as follows:
  1. Enable/Disable condition
  2. Switch condition
  3. Enable/Disable join table with condition

Enable/Disable Condition

Use this pattern when the condition in the “where” clause is dependant of a parameter.
For example, we need to perform some procedure with either all Customer or Customers with invoice account only. It depends on the User input parameter. We create a periodic job with the following dialog box:

Process Customers
Process Customers


We will assume that the Customer with invoice account check box has the dialogField name in the code.
The select statement will have the following view in the “run” method:
while select custTable
where (!dialogField.value() || custTable.InvoiceAccount != '')
If the check box is selected, !dialogField.value() returns false and custTable.InvoiceAccount != ” will be taken into account. If the check box isn’t selected, !dialogField.value() returns true (so there is no sense what return the custTable.InvoiceAccount != ” condition). In other words, if the check box is selected, only Customers with Invoice accounts will be searched. Otherwise, all Customers will be searched.
General structure looks as follows: where (!EnableConditionFlag || condition)

Switch Condition

Use this pattern when either one or another condition dependant of parameter must be applied to the select statement.
For example, we need to perform a procedure with items of either a BOM item or items of other item types. We need to create a periodic job with a dialog box. The dialog box contains only one BOM type checkbox. We will assume that the BOM type check box has the dialogField name in the code.
In the run method, we write the following select statement:
while select inventTable
where ((!dialogField.value() && inventTable.ItemType != ItemType::BOM) ||
       (dialogField.value()  && inventTable.ItemType == ItemType::BOM))
If the BOM type check box is selected, the first parenthesis returns false and everything depends on the second parenthesis where the inventTable.ItemType == ItemType::BOM clause is checked. If the BOM type check box isn’t selected, the second parenthesis returns false and everything depends on the first parenthesis where the inventTable.ItemType != ItemType::BOM clause is checked. In other words, if the check box is selected, the only BOM item will be searched. Otherwise, only not BOM items will be searched.
General structure looks as follows: where ((!Condition2Flag && condition 1) || (Condition2Flag && condition 2))

Enable/Disable Join Table with Condition

Use this pattern when a joined table with a condition can either contain records or be empty.
For example, we need select sales orders without Recipient or terminated Recipient. The SalesTaker field in the SalesTable table stores the Recipient ID. The Status field in the EmplTable table stores the Recipient’s status (None, Employed, or Resigned).
The select statement has the following view:
while select SalesTable
notexists join EmplTable
where EmplTable.EmplId == SalesTable.SalesTaker &&
      EmplTable.status != HRMEmplStatus::Resigned
If EmplTable.status is Resigned or the Sales table record doesn’t have the Recipient, the Sales table record will be selected.
General structure looks as follows: notexists join <TableName> where <relation clause> && (condition != required value)
If you know other interesting patterns, please write them in the comments ;)


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian   

Search in AOT


Searching in AOT groups like Classes, Forms, etc. by scanning tree nodes is unacceptable due to performance reasons. For searching in AOT groups you should scan system table UtilElements. See example in SysAotFind form – class SysUtilScanSource.


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

Module logo


Hi! I have received the following task: Create new module in Dynamics AX and assign image or logo to this module.
Let’s develop this task.
Module is created very easy:
  1. Go to the AOT > Menus and create new menu.  For example TestMenu.
  2. Add menu item. For example CustTable menu item.
  3. Then create new menu reference in the MainMenu menu:
    • On the MainMenu menu clicks the right mouse button and select New > Menu reference. The Select: Menus windows opens.
    • Drag and drop the TestMenu menu from Select:Menus window to the MainMenu.
New menu
New menu


This is all. The new module have been added. Reopen Dynamics AX application.
The new modules appears without image (to move module on the top position clicks the Microsoft Dynamics AX >View > Navigate Pane Options…):

New module without logo
New module without logo


Adding module logo is not so easy. Select the TestMenu menu in the AOT, click right mouse button and select Properties. There are two properties NoramlImage and NormalResource.

Menu properties
Menu properties


In the NormalImage property the file path to the logo could be specified. But if we create product for sell then we can not specify the exact file path because each Customer will have own path.
In the NormalResource property the image id could be specified. It is suitable for our requirements. Let’s add image in Dynamics AX:
  1. Go to the AOT > Resources. Click right mouse button and select Create form file.
  2. Specify the file path and click Open.
The new image resource will be created:

Image resource
Image resource


But this resource doesn’t have the resource id or image id property. Even more in the NormalResource property only the resource id of standard image can be specified. Standard image could be review here AOT > Forms > SysImageResources.
Trick: we will use the NormalImage property and Logo_image_png resource.
Create the following static method:
static client void addImageToModule()
{
TreeNode treeNodeMenu;
;

treeNodeMenu = SysDictMenu::newMenuName(menustr(TestMenu)).parmTreeNode();
if (treeNodeMenu)
{
treeNodeMenu.AOTsetProperty(identifierstr(NormalImage), SysResource::getImagePath(resourcestr(Logo_image_png)));
treeNodeMenu.AOTsave();
}
}

Call this method in the \Classes\Application\startupPost method:

// No SYS code must exist in this method
// If you need the startup command, look in the class SysStartupCmd
void startupPost()
{
;
Class1::addImageToModule();
}

Reopen application.

Module with logo
Module with logo


All the best ;)





Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

InventOnHand vs InventDimOnHand


What the difference between InventOnHand and InventDimOnHand classes and in what cases they must be used?
Axapta InventOnHand class is wrapper for InventSum table. Unique index for InventSum table is ItemId + InventDimId. In other word, this class is used to get on hand for item with specific dimension. For example, if you require getting on-hand qty for “Bottle” items that have “green” color, “standard” size and are stored in “22” warehouse, “1” Aisle, “4” Shelf then you use InventOnHand class.
But, if you require getting on-hand qty for warehouse location then InventOnHand class couldn’t help us. Because one location could contains different items. Or if you require get on-hand qty for pallet. In these cases InventDimOnHand class must be used. This class is used when you require on-hand qty for specific inventDim. InventDimOnHand сlass consists of InventDimOnHandMember classes. Each InventDimOnHandMember class contains information about Item, Dimensions and Qty.
Example: “Get location on-hand”
static void rmsOnHandQty(Args _args)
{
WMSLocation wmsLocation;
InventDim inventDimLocal;
InventDimParm inventDimParmCriteria;
InventDimOnHand inventDimOnHand;
InventDimOnHandIterator inventDimOnHandIterator;
InventDimOnHandMember inventDimOnHandMember;
Qty qty;
;

select firstonly wmsLocation;
inventDimLocal.InventLocationId = wmsLocation.inventLocationId;
inventDimLocal.wMSLocationId = wmsLocation.wMSLocationId;
inventDimLocal = InventDim::findOrCreate(inventDimLocal);
inventDimParmCriteria.wmsLocationIdFlag = NoYes::Yes;
inventDimParmCriteria.InventLocationIdFlag = NoYes::Yes;
inventDimOnHand = InventDimOnHand::newPhysicalArrived('', inventDimLocal, inventDimParmCriteria, inventDimOnHandLevel::Item, null);
inventDimOnHandIterator = inventDimOnHand.onHandIterator();
while (inventDimOnHandIterator.more())
{
inventDimOnHandMember = inventDimOnHandIterator.value();
qty += inventDimOnHandMember.parmInventQty();
inventDimOnHandIterator.next();
}
info(strfmt("%1 location has %2 items", wmsLocation.wMSLocationId, num2str(qty,2,2,1,1)));
}



Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

How to use select statements instead of query in data source


Override FormDataSource method executeQuery:
    public void executeQuery()
    {
        SomeTable T = this.cursor();

        select * from T where …;
    }
But be aware that in this case grid will not support sorting and filtering.


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

How to set focus when first time opening form


Override method firstField on a form, and call after super method setFocus of a control which should focused after form is opened. Example:
    public void firstField(int _flags=1)
    {
        ;
        super(_flags);
        MyControlName.setFocus();
    }


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

How to override lookup


void SummaryProjectLookup(FormControl ctrl)
{
    SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum(ProjTable),ctrl);
    Query query = New Query();
    QueryBuildDataSource queryBuildDataSource = query.addDataSource(tableNum(ProjTable));
    QueryBuildRange queryBuildRange;
    ;

    sysTableLookup.addLookupfield(fieldNum(ProjTable, ProjId));
    sysTableLookup.addLookupfield(fieldNum(ProjTable, Name));
    sysTableLookup.addLookupfield(fieldNum(ProjTable, Status));

    queryBuildRange = queryBuildDataSource.addRange(fieldNum(ProjTable, Type));
    queryBuildRange.value(queryValue(ProjType::Summary));
    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();
}

public void lookup()
{
    element.SummaryProjectLookup(this);
}


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

How to make dialog fields mandatory


See example below on how implement mandatory fields in dialog:
    boolean             ret;
    FilePath            workFolder;

    Dialog              dlg;
    DialogField         dfWorkFolder;
    FormStringControl   fsc;
    FormGroupControl    fgc;
    ;

    dlg             = new Dialog( "@CDT135" );
    dfWorkFolder    = dlg.addField( typeid( FilePath ), "@CDT136" );
    fgc             = dlg.mainFormGroup();
    fsc             = fgc.controlNum( 1 ); fsc.mandatory( true );

    while( dlg.run() )
    {
        workFolder  = dfWorkFolder.value();

        if( workFolder)
        {
            ret     = true;
            break;
        }

        dlg.doInit();
    }


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

How to make data from temporary table available in form’s grid


Code in form’s outer scope:

TmpTable  tmpTable;
FormRun        formRun;
;
...
// Fill tmpTable with data here
…
args.record( tmpTable );
formRun = classFactory.formRunClass( args );
formRun.init();
formRun.run();
formRun.detach();
formRun.wait();
if( formRun.closedOk() )
{
 …
// Process data from tmpTable updated in form here
 …
}
Code in form, in the temporary table datasource – TmpTableDS:

public void init()
{
    TmpTable  tmpTable;
    ;

    tmpTable = element.args().record();

    super();

    TmpTableDS.setTmpData( tmpTable );
}


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

How to get original value for table fields during record modification


Use table method orig(). It returns the orig buffer which is the committed version of the record in the database.


Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian  

How to get current language


 xInfo inf;

    ;

    inf = new xInfo();

    if( inf )

    {

        inf.language();

    }



Copied from Experts website....... Dynamicsaxtraining.
You can always reach me at axapta4all@gmail.com
Anonymous Axaptian