Working with Forms in Dynamics AX: Part 3

Exclusive offer: get 50% off this eBook here
Microsoft Dynamics AX 2009 Development Cookbook

Microsoft Dynamics AX 2009 Development Cookbook — Save 50%

Solve real-world Microsoft Dynamics AX development problems with over 60 simple but incredibly effective recipes with this book and eBook

£18.99    £9.50
by Mindaugas Pocius | December 2009 | .NET Cookbooks Microsoft

Read Part One of Working with Forms in Dynamics AX here.

Read Part Two of Working with Forms in Dynamics AX here.

Building checklists

Anyone who preformed Dynamics AX application installation or upgrade has to be familiar with standard checklists. Normally, a checklist is a list of menu items displayed in logical sequence. Each item represents either mandatory or optional actions to be executed by the user in order to complete the whole procedure. In custom Dynamics AX implementations, checklists can be used as a convenient way to configure non standard settings. Checklists can also be implemented as a part of third-party modules for their initial setup.

In this recipe, we will create a checklist for user-friendly ledger budget setup. The checklist will consists of two mandatory and one optional item.

How to do it...

  1. Open AOT, and create a new class called SysCheckListInterfaceBudget:

    interface SysCheckListInterfaceBudget
    extends SysCheckListInterface
    {
    }
  2. Create three more classes—one for each checklist item, with the following code:
    class SysCheckListItem_BudgetModel
    extends SysCheckListItem
    implements SysCheckListInterfaceBudget
    {
    }
    public str getCheckListGroup()
    {
    return "Setup";
    }
    public str getHelpLink()
    {
    #define.TopicId('AxShared.chm::/html/' +
    '84030522-0057-412C-BFC7-DBEB4D40E5A1.htm')
    ;
    return SysCheckListItem::sharedGuide(#TopicId);
    }
    public MenuItemName getMenuItemName()
    {
    return menuitemdisplaystr(BudgetModel);
    }
    public MenuItemType getMenuItemType()
    {
    return MenuItemType::Display;
    }
    str label()
    {
    return "Models";
    }
    class SysCheckListItem_BudgetRevision
    extends SysCheckListItem
    implements SysCheckListInterfaceBudget
    {
    }
    public void new()
    {;
    super();
    this.placeAfter(classnum(SysCheckListItem_BudgetModel));
    this.indeterminate(true);
    }
    public str getCheckListGroup()
    {
    return "Setup";
    }
    public str getHelpLink()
    {
    #define.TopicId('AxShared.chm::/html/' +
    'AACC4353-C3EB-4982-BB7F-2B36D97FF25B.htm')
    ;
    return SysCheckListItem::sharedGuide(#TopicId);
    }
    public MenuItemName getMenuItemName()
    {
    return menuitemdisplaystr(BudgetRevision);
    }
    public MenuItemType getMenuItemType()
    {
    return MenuItemType::Display;
    }
    str label()
    {
    return "Revisions";
    }
    class SysCheckListItem_Budget
    extends SysCheckListItem
    implements SysCheckListInterfaceBudget
    {
    }
    public void new()
    {;
    super();
    this.addDependency(
    classnum(SysCheckListItem_BudgetModel));
    this.placeAfter(
    classnum(SysCheckListItem_BudgetRevision));
    }
    public str getCheckListGroup()
    {
    return "Create budgets";
    }
    public str getHelpLink()
    {
    #define.TopicId('AxShared.chm::/html/' +
    '6A596E1E-6803-4410-B4E4-EDE4EF44AF6D.htm')
    ;
    return SysCheckListItem::sharedGuide(#TopicId);
    }
    public MenuItemName getMenuItemName()
    {
    return menuitemdisplaystr(LedgerBudget);
    }
    public MenuItemType getMenuItemType()
    {
    return MenuItemType::Display;
    }
    str label()
    {
    return "Budgets";
    }

  3. Create another class for the checklist itself:
    class SysCheckList_Budget extends SysCheckList
    {
    container log;
    }
    protected str getCheckListCaption()
    {
    return "Budget checklist";
    }
    protected str getHtmlHeader()
    {
    return "Budget checklist";
    }
    protected classId getInterfaceId()
    {
    return classnum(SysCheckListInterfaceBudget);
    }
    public void save(
    identifiername _name,
    ClassDescription _description)
    {;
    if (!confind(log, _name))
    {
    log = conins(log, conlen(log)+1, _name);
    }
    }
    public boolean find(
    identifiername _name,
    ClassDescription _description)
    {
    return confind(log, _name) ? true : false;
    }
    static void main(Args _args)
    {;
    SysCheckList::runCheckListSpecific(
    classnum(SysCheckList_Budget),
    true);
    }
  4. Open the SysCheckList class in AOT, and replace its checkListItemsHook() and checkListsHook() with the following code:
    protected static container checkListsHook()
    {
    return [classnum(SysCheckList_Budget)];
    }
    protected static container checkListItemsHook()
    {
    return [classnum(SysCheckListItem_Budget),
    classnum(SysCheckListItem_BudgetRevision),
    classnum(SysCheckListItem_BudgetModel)];
    }
  5. Open the BudgetModel form in AOT, and override its close() with the following code:
    public void close()
    {;
    super();
    SysCheckList::finished(
    classnum(SysCheckListItem_BudgetModel));
    }
  6. Open the BudgetRevision form in AOT, and override its close() with the following code:

    public void close()
    {;
    super();
    SysCheckList::finished(
    classnum(SysCheckListItem_BudgetRevision));
    }
  7. Open the LedgerBudget form in AOT, and override its close() with the following code:
    public void close()
    {;
    super();
    SysCheckList::finished(
    classnum(SysCheckListItem_Budget));
    }
  8. Create a new Display menu item SysCheckList_Budget with the following properties:

Property

Value

Name

SysCheckList_Budget

Label

Budget checklist

ObjectType

Class

Object

SysCheckList_Budget

  1. To test the checklist, run the SysCheckList_Budget menu item from AOT. The following should appear on the right-hand side of the Dynamics AX window:

    Microsoft Dynamics AX 2009 Development Cookbook

  2. Click on the listed items to start and complete relevant actions. Notice how the status icons change upon completion of each task.

    Microsoft Dynamics AX 2009 Development Cookbook

How it works...

The main principle behind checklists is that we have to create a main class, which represents the checklist itself and a number of SysCheckListItem item classes, which act as list items. The relation between the main class and the items is made by the use of an interface, that is, each list item implements it, and the main class holds the reference to it.

In this example, we create an interface SysCheckListInterfaceBudget and specify it in the getInterfaceId() of the main checklist class SysCheckList_Budget. Next, we implement the interface in three SysCheckListItem classes, which correspond to Models, Revisions, and Budgets items in the checklist.

Each SysCheckListItem class contains a set of inherited methods, which allows us to define a number of different parameters for individual items:

  • All initialization code can be added to the new() methods. In this example, we use placeAfter() to determine the position of the item in the list relative to other items, indeterminate() to make item optional and addDependency() to make an item inactive until another specified item is completed.
  • getCheckListGroup() defines item dependency to a specific group. The Budget checklist has two groups, Setup and Create budgets.
  • getHelpLink() is responsible for placing the relevant help link in the form of a question mark next to the item.
  • getMenuItemName() and getMenuItemType() contain a name and a type of menu item, which is executed upon user request. Here, we have Budget model, Budget revisions, and Ledger budget forms respectively in each class.
  • And finally custom labels can be set in label().

Once the items are ready, we create the main checklist class SysCheckList_Budget, which extends the standard SysCheckList. We override some of the methods to add custom functionality to the checklist:

  • getCheckListCaption() sets the title of the checklist.
  • getHtmlHeader() could be used to add some descriptive text.
  • As mentioned before, getInterfaceId() is the place where we specify the name of the checklist item interface.
  • The methods save() and find() are used to store and retrieve respectively the status of each item in the list. In this example, we store statuses in the local variable log to make sure that statuses are reset every time we run the checklist.
  • The static method main() runs the class. Here, we use runCheckListSpecific() of the system SysCheckList class to start the checklist.

The display menu item we created is pointing to the checklist class and may be used to add the checklist to a user menu.

When building checklists, it is necessary to add them and their items to the global checklist and checklist item list. The SysCheckList class contains two methods—checkLists() and checkListItems()—where all system checklists and their items are registered. The same class provides two more methods—checkListsHook() and checkListItemsHook()—where custom checklists should be added. As a part of this example, we also add our budget checklist and its items to the SysCheckList.

Final modifications have to be done in all checklist forms. We call the finished() of the SysCheckList class in the close() of each form to update the status of the corresponding checklist item. In other words, it means that item status will be set as completed when the user closes the form. This code does not affect the normal use of the form when it is opened from the regular menu. Of course, more logic could be added here if the completion of a specific item is not that straightforward.

Also notice that the system automatically adds a link called Information, which describes the checklist statuses:

Microsoft Dynamics AX 2009 Development Cookbook

There's more...

The checklist in this example stores item statuses per each run. This means that every time you close the checklist, its statuses are lost and are set to their initial states upon checklist start. By replacing save() and find() in SysCheckList_Budget with the following code, we can store statuses permanently in the SysSetupLog table:

public boolean find(
identifiername _name,
ClassDescription _description)
{
return SysSetupLog::find(_name, _description).RecId != 0;
}
public void save(
identifiername _name,
ClassDescription _description)
{;
SysSetupLog::save(_name, _description);
}

In this case, every time the checklist starts, the system will pick up its last status from the SysSetupLog table and allow the user to continue the checklist.

Adding a "Go to the Main Table Form" link

Go to the Main Table Form is a feature of Dynamics AX, which allows users to jump to the main record just by right-clicking on the field and selecting the Go to the Main Table Form option. It is based on table relations and is available for those controls whose data fields have foreign key relationships with other tables.

Because of the data structure integrity, this feature works most of the time. However, when it comes to complex table relations, it does not work correctly or does not work at all. Another example of when this feature does not work automatically is when the form control is not bound to a table field. In such situations, Go to the Main Table Form has to be implemented manually.

In this recipe, to demonstrate how it works, we will modify the Business relations form in the CRM module to make sure that the Employee filter at the top of the form allows users to use the Go to the Main Table Form feature from the context menu.

How to do it...

  1. Open the smmBusRelTable form in AOT, and override jumpRef() of the EmployeeFilter control with:
    public void jumpRef()
    {
    EmplTable emplTable;
    Args args;
    MenuFunction menuFunction;
    ;
    emplTable = EmplTable::find(this.text());
    if (!emplTable)
    {
    return;
    }
    args = new Args();
    args.caller(element);
    args.record(emplTable);
    menuFunction = new MenuFunction(
    menuitemdisplaystr(EmplTable),
    MenuItemType::Display);
    menuFunction.run(args);
    }
  2. To test the result, open CRM | Business Relation Details, make sure an employee number is specified in the Employee filter, and right-click on the filter control. Notice that the Go to the Main Table Form option, which will open the Employee form, is now available:
    Microsoft Dynamics AX 2009 Development Cookbook

How it works...

Normally, the Go to the Main Table Form feature is controlled by the relations between tables. If there are no relations or the form control is not bound to a table field, then this option is not available. But, we can force this option to appear by overriding the control's jumpRef() method.

In this method, we have to add code that opens the relevant form. This can be done by creating, initializing, and running a FormRun object, but the easier way is to simply run the relevant menu item. In this recipe, the code in jumpRef() does exactly that.

First, we check if the value in the control is a valid employee number. If yes, then we run the Display menu item EmplTable with an Args object containing the proper employee record. The rest is done automatically by the system, that is, the Employee form is opened with the employee information.

Microsoft Dynamics AX 2009 Development Cookbook Solve real-world Microsoft Dynamics AX development problems with over 60 simple but incredibly effective recipes with this book and eBook
Published: December 2009
eBook Price: £18.99
Book Price: £30.99
See more
Select your format and quantity:

Modifying the User setup form

The User setup form allows users to customize their most often used forms to fit their needs. Users can hide or move form controls, change labels, and so on. The setup is available for any Dynamics AX form and can be opened from the right-click context menu by selecting the Setup option.

As a developer, I also use this form very often. For example, it contains the very handy System name field, which displays the name of the currently selected table field or method, so you do not need to search in AOT. The Information tab page provides information about the form itself, the caller object, and the menu item used, and it allows opening those objects instantly in AOT view. The last tab page Query shows the tables used in the form's query, which is also very useful to quickly understand the underlying data structure.

In this recipe, we will enhance the User setup form. We will add a new button to the last tab page, which will open the selected table in AOT.

How to do it...

  1. Open SysSetupForm form in AOT, and replace the following code in its fillQueryTreeQueryDatasource():

    formTreeItem = new FormTreeItem(
    nodeText,
    imagelist.image(#ImageDataSource),
    -1,
    null);

    with the code:

    formTreeItem = new FormTreeItem(
    nodeText,
    imagelist.image(#ImageDataSource),
    -1,
    queryBuildDataSource.table());
  2. Add a new ButtonGroup to the QueryPage tab page:

Property

Value

Name

ButtonGroup1

  1. Add a new Button to the created button group:
Property Value
Name EditTable
Text Edit
AutoDeclaration Yes
  1. Override the button's clicked() method:
    void clicked()
    {
    FormTreeItem formTreeItem;
    TableId tableId;
    TreeNode treeNode;
    #AOT
    ;
    formTreeItem = QueryTree.getItem(
    QueryTree.getSelection());
    tableId = formTreeItem.data();
    if (!tableId || !tableid2name(tableId))
    {
    return;
    }
    treeNode = infolog.findNode(
    #TablesPath +
    #AOTDelimiter +
    tableid2name(tableId));
    if (!treeNode)
    {
    return;
    }
    treeNode.AOTnewWindow();
    }
  2. Override selectionChanged() on the QueryTree control:
    public void selectionChanged(
    FormTreeItem _oldItem,
    FormTreeItem _newItem,
    FormTreeSelect _how)
    {;
    super(_oldItem, _newItem, _how);
    EditTable.enabled(
    tableid2name(_newItem.data())?true:false);
    }
  3. To test, open any form, for example, Chart of Account Details from the General ledger, and open User setup by right-clicking anywhere on the form and selecting the Setup option:
    Microsoft Dynamics AX 2009 Development Cookbook
  4. Go to the Query tab page, and select one of the tables in the query displayed:

    Microsoft Dynamics AX 2009 Development Cookbook

  5. Click the Edit button to open this table in AOT:

    Microsoft Dynamics AX 2009 Development Cookbook

How it works...

First, we modify the creation of the query tree control. Normally, each tree node can hold some data. The tree in the SysSetupForm form does not have any data associated with nodes, so we have to modify the code and store the table number in each node representing a table.

Next, we add a new button and override its clicked(). In this method, we get the table number stored in the currently selected node—this is what we stored earlier—and search for that table in AOT. We display it in a new AOT window if found.

Finally, we override selectionChanged() on the QueryTree control to make sure the button's status is updated upon node selection. In other words, the Edit button is enabled if the current tree node contains some data, otherwise it is disabled.

In this way, we have modified the User setup form to provide us with a quick AOT access to the underlying tables.

Modifying application version

Dynamics AX identifies its releases with two version numbers—kernel version and application version. For example, version number 5.0.593.0 means Dynamics AX 2009 RTM and 5.0.1000.52 is Dynamics AX 2009 Service Pack 1. Dynamics AX hotfix rollups are presented in a similar way by only updating the last version number digits. Version numbers an be viewed in the About Microsoft Dynamics AX dialog, which can be accessed from the Help menu.

Besides standard versioning, Dynamics AX allows adding additional versions for solution developers to control their releases. In this recipe, we will learn how to do that. We will modify standard application objects to incorporate our changes.

Getting ready

Solution versions can be changed only in SL1, SL2, SL3, BUS (and BUP) layers. SL1-SL3 layers are used for certified solutions and BUS—for business partner solutions. To proceed further, we will need the BUS layer code in order to log in to the BUS and BUP layers of the application.

How to do it...

  1. Log in to the BUS layer, and modify sLxAppl() of the ApplicationVersion class to:
    private static client str sLxAppl()
    {
    return '1.0.0';
    }

  2. Log in to the BUP layer, and modify the same method to:
    private static client str sLxAppl()
    {
    return '2.0.0';
    }

  3. The class in AOT should look like this:

    Microsoft Dynamics AX 2009 Development Cookbook

  4. Open Help | About Microsoft Dynamics AX, and notice the Solution version numbers:

    Microsoft Dynamics AX 2009 Development Cookbook

How it works...

The ApplicationVersion class is the place where application version numbers are stored. For example, applBuildNo() returns the current application version. By modifying this class, Dynamics AX developers can modify original or custom version numbers. Later this class is called from the SysAbout form, which is actually the About Microsoft Dynamics AX dialog.

The class already contains a special method sLxAppl(), which should be used when defining a custom solution version. The interesting point is that different version numbers can be stored in different layers. In our example, first we set a version in BUS, and then we change that version in the BUP layer. And the result is that we can see both numbers separated by a slash in the About Microsoft Dynamics AX dialog. The text Solution version is added automatically, though it could be also changed.

There's more...

Every Dynamics AX implementation project contains more or less customer-specific changes. Regardless of how big the modifications are, it is a good practice to use versioning. The modifications are normally stored in the VAR layer or any layer above it and are not included in automatic version display. However, if we look at the run() of the SysAbout form, we could notice that the information displayed on this form is actually formatted here. We can add our own code and relevant control to the form itself to display the custom name and version. So let's improve previous example and add an additional version called VAR version.

To follow existing practice, let's add one more method in the ApplicationVersion class first. (Do not forget to logout of BUP layer and log into your working layer). It will hold our version number:

static str varAppl()
{
return '3.0.0';
}

In AOT, open SysAbout form and add a new StaticText control for displaying version-related information with the following properties:

Property

Value

Name

VARVersion

AutoDeclaration

Yes

Width

Column width

BackStyle

Transparent

Text

 

The form in AOT should look like following:

Microsoft Dynamics AX 2009 Development Cookbook

And finally, we modify the form's run(). Let's add:

str varVersionNumber = ApplicationVersion::varAppl();

right after:

str slxVersionNumber = ApplicationVersion::sLxApplAll();

and:

if (varVersionNumber)
{
VARVersion.text('VAR version: ' + varVersionNumber);
}

right after:

if (slxVersionNumber)
{
solutionVersion.text('Solution version: ' +
slxVersionNumber);
}

Now, open Help | About Microsoft Dynamics AX again, and notice a new entry—VAR version:

Microsoft Dynamics AX 2009 Development Cookbook

In this way, you can customize the display of the About Microsoft Dynamics AX dialog to ensure that any custom modification or module is listed here along with its version for user information.

Summary

This article covered the various aspects of using Dynamics AX forms. In this article, dialogs and their events were explained. Various useful features like splitters, saving last values, changing form appearance, dynamic controls, and others were also explained.

[ 1 | 2 | 3 ]

 

If you have read this article you may be interested to view :

Microsoft Dynamics AX 2009 Development Cookbook Solve real-world Microsoft Dynamics AX development problems with over 60 simple but incredibly effective recipes with this book and eBook
Published: December 2009
eBook Price: £18.99
Book Price: £30.99
See more
Select your format and quantity:

About the Author :


Mindaugas Pocius

Mindaugas Pocius is currently a freelance Dynamics AX technical and functional consultant and trainer at DynamicsLab Limited (http://www.dynamicslab.com). The company specializes in providing development, consulting, and training services for Microsoft Dynamics AX resellers and customers.

Mindaugas started his IT consultant career back in 2001 while still in his Information Technology Master Studies at a Lithuanian University. Since then he has become a recognized Microsoft Certified Professional for Dynamics AX in most of the major areas: Development, Configuration & Installation, Financials, Trade & Logistics and Project Management. He is also a Certified Microsoft Trainer for Dynamics AX and has delivered Dynamics AX Development, Finance and other training across the world. From 2001 to 2012, Mindaugas participated in numerous Dynamics AX implementations, ranging from small local to large international projects reaching an 800 strong user base. He has held a wide range of development, consulting, and leading roles while always maintaining a significant role as a business application developer.

Books From Packt

 

Ext JS 3.0 Cookbook
Ext JS 3.0 Cookbook

Joomla! 1.5 Development Cookbook
Joomla! 1.5 Development Cookbook

WordPress 2.7 Cookbook
WordPress 2.7 Cookbook

WordPress 2.8 Themes Cookbook
WordPress 2.8 Themes Cookbook

Microsoft Dynamics AX 2009 Programming: Getting Started
Microsoft Dynamics AX 2009 Programming: Getting Started

Programming Microsoft Dynamics NAV 2009
Programming Microsoft Dynamics NAV 2009

Microsoft Office Live Small Business: Beginner’s Guide
Microsoft Office Live Small Business: Beginner’s Guide

Quality Assurance for Dynamics AX-Based ERP Solutions
Quality Assurance for Dynamics AX-Based ERP Solutions

 

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software