Microsoft Dynamics AX Programming Getting lesforgesdessalles.info · Add files via upload, 2 years ago. Microsoft Dynamics AX Development lesforgesdessalles.info In December , he released his first book, Microsoft Dynamics AX Development Cookbook, both of which are published by Packt Publishing. . know that Packt offers eBook versions of every book published, with PDF and ePub. AX Development Cookbook, lesforgesdessalles.info%5Chide%5CAX5% 5CeBooks%5CAXebook%20AX%lesforgesdessalles.info
|Language:||English, Spanish, Dutch|
|ePub File Size:||20.35 MB|
|PDF File Size:||10.39 MB|
|Distribution:||Free* [*Regsitration Required]|
Microsoft Dynamics. AX Development. Cookbook. Solve real-world Dynamics AX development problems with over 60 simple but incredibly effective . Microsoft Dynamics AX Development Cookbook. As a Dynamics AX developer, your responsibility is to deliver all kinds of application customizations . Microsoft Dynamics AX Development Cookbook Solve real-world DOWNLOAD PDF First published: December Second edition: May
Here we use the kernelCheckTable member method, which validates the given table. Name ; nodeTable. Processing Data 7 Introduction 7 Creating a new number sequence 8 Renaming the primary key 13 Merging two records 17 Adding a document handling note 19 Using a normal table as a temporary table 21 Copying a record 22 Building a query object 25 Using a macro in an SQL statement 30 Executing a direct SQL statement 31 Enhancing the data consistency check 37 Exporting data to an XML file 41 Importing data from an XML file 44 Creating a comma-separated value file 46 Reading a comma-separated value file 49 Using the date effectiveness feature 52 Chapter 2: The modified class should look similar to the following code: We just need to create an additional method to allow running of the class: Add the account number node to the table node.
Site Search User. Thread information. Share More Cancel. Click here to login or become a member to ask questions and reply in our fourms. Offline David Singleton over 11 years ago. Up 0 Down Cancel. Offline munib over 9 years ago in reply to tamer. Getting Started" http: You are both criminals. They are commonly used for small user tasks, such as filling in report values, running batch jobs, presenting only the most important fields to the user when creating a new record, and so on.
The application class Dialog is used to build dialogs. A common way of using dialogs is within the RunBase framework classes, where user input is required.
In this example, we will demonstrate how to build a dialog from the code using the RunBase framework class. The dialog will contain customer table fields shown in different groups and tabs for creating a new record. There will be two tab pages, General and Details. The first page will have Customer account and Name input controls. The second page will be divided into two groups, Setup and Payment, with relevant fields inside each group.
The actual record will not be created, as it is out of scope of this example. However, for demonstration purposes, the information specified by the user will be displayed in the Infolog.
In order to test the dialog, run the class. The following form should appear with the General tab page open initially: Click on the Details tab page to see the following screen: Enter some information into the fields and click OK. The results are displayed in the Infolog: First, we create a new class CustCreate.
By extending it from RunBase, we utilize a standard approach of developing data manipulation functions in Dynamics AX.
The RunBase class defines a common structure and automatically adds additional controls, such as OK and Cancel buttons to the dialog. Then we declare class member variables, which will be used later.
Variables of the DialogField type represent user input fields. Other variables are used to store the actual user input. RunBase requires those two methods to be implemented in all its subclasses. The layout of the actual dialog is constructed in the dialog member method.
Here, we define local variables for the dialog itself—tab pages and groups. Those variables, as opposed to the dialog fields, do not store any value for further processing.
The super of the RunBase framework creates the initial dialog object for us. The object is created using the Dialog application class. The class actually uses an AOT form named Dialog as a base, automatically adds the relevant controls, including OK and Cancel buttons, and presents it to the user as a dialog.
Additional controls are added to the dialog by using the addField , addGroup , and addTabPage methods.
There are more methods to add different types of controls, such as addText , addImage , addMenuItemButton , and others. All controls have to be added to the dialog object directly.
Adding an input control to groups or tabs is done by calling addField right after addGroup or addTabPage. In the previous example, we added tab pages, groups, and fields in logical sequence top down. Notice that it is enough only to add a second tab page, the first one labeled General is added automatically by the RunBase framework. Values from the dialog controls are assigned to variables by calling the value member method of the DialogField class.
If a dialog is used within the RunBase framework, as in this example, the best place to assign dialog control values to variables is the getFormDialog member method. RunBase calls this method right after the user clicks OK. The main processing is done in the run method. For demonstration purposes, this class only shows the user input the Infolog. In order to make this class runnable, the static method main has to be created. Here, we create a new CustCreate object, invoke user dialog by calling the prompt method, and once the user finishes entering customer details by clicking OK, we call the run method to process the data.
See also In this chapter: For example, if the user marks the Show filter checkbox, then another field, Filter, appears or becomes enabled. In AOT forms, this can be done by using the input control modified event. However, if this feature is required on runtime dialogs, handling events are not that straightforward. Very often, existing dialogs have to be modified to support eventing. The easiest way of doing that is of course to convert a dialog into an AOT form. However, in cases when the existing dialog is complex enough, probably a more cost effective solution would be to implement dialog event handling instead of converting it into an AOT form.
Event handling in dialogs is not as flexible as in AOT forms, but in most cases it does the job. In this recipe, we will create a dialog very similar to the previous one, but instead of entering the customer number, we will be able to select it from the list. Once the customer is selected, the rest of the fields will be completed automatically by the system from the customer record.
CustGroup ; fieldCurrency. Currency ; fieldPaymTermId. PaymTermId ; fieldPaymMode. Run the class, select any customer from the list, and move the cursor to the next control. Notice how the rest of the fields were populated automatically with the customer information: When you click on the Details tab page, you will see the details as shown in the following screenshot: The new class CustSelect is actually a copy of the CustCreate class from the previous recipe with a few changes.
In its class declaration, we leave all DialogField declarations and remove the rest of the variables. In the dialog member method, we call the allowUpdateOnSelectCtrl method with the argument true to enable input control event handling.
We also disable all controls apart from the Customer account by calling enable with parameter false for each control. The member method dialogSelectCtrl of the RunBase class is called every time the user modifies any input control in the dialog. It is the place where we have to add all the required code to ensure that, in our case, all controls are populated with the correct data from the customer record, once the Customer account is chosen.
The static main method ensures that we can run this class. Usage of the dialogSelectCtrl method sometimes might appear a bit limited as this method is only invoked when the dialog control loses its focus.
Also, no other events can be controlled, and it can become messy if events on multiple controls need to be processed. The Dialog class does not provide direct access to the underlying form's event handling functions, but we can easily access the form object within the dialog. Although we cannot create the usual event handling methods on runtime form controls, we can still control this in a slightly different way.
Let us modify the previous example to include more events. We will add an event on the second tab page, which is triggered once the page is activated.
First, we have to override the dialogPostRun method on the CustSelect class: We also pass the CustSelect object as an argument to the controlMethodOverloadObject method to make sure that the form knows where the overloaded events are located. Now run the class again, and select the Details tab page.
The message should be displayed in the Infolog. Before creating such methods, we first have to get the name of the runtime control.
This is because the dialog form is created dynamically, and the system defines control names automatically without allowing the user to choose them. In this example, we have to temporarily add the following code to the bottom of the dialog , which displays the name of the Details tab page control.
Just replace the following code: Note that this approach may not work properly if the dialog contains an automatically-generated query. In such cases, control names will change if the user adds or removes query ranges. Using this approach, it is possible to achieve a high level of complexity.
However, in a number of cases, it is required to have forms created dynamically. In the standard Dynamics AX application we can see that application objects, such as the Table browser form, various lookups, or dialogs, are built dynamically. In this recipe, we will create a dynamic form. In order to show how flexible it can be, we will replicate the layout of the existing Customer groups form located in the Accounts receivable module.
It can be opened from Accounts receivable Setup Customers. SimpleList ; design. ActionPane, 'ActionPane' ; actionPane. CommandButton, 'NewButton' ; cmdNew. TextAndImageLeft ; cmdNew. EmbeddedResource ; cmdNew. Yes ; cmdNew. CommandButton, 'NewButton' ; cmdDel. TextAndImageLeft ; cmdDel. EmbeddedResource ; cmdDel. Yes ; cmdDel. MenuFunctionButton, 'Posting' ; mibPosting.
No ; mibPosting. No ; mibForecast. Group, 'Body' ; grpBody. ColumnHeight ; grpBody. Grid, "Grid" ; grid. ColumnWidth ; 69 Working with Forms grid. ColumnHeight ; grid. In order to test the form, run the class. Notice that the form is similar to the one in Accounts receivable Setup Customers Customer groups: We start the code by declaring some variables. Note that most of them begin with FormBuild, which is part of a set of the application classes used for building dynamic forms.
Each of these types correspond to the control types manually used when building forms in the AOT. Right after the variable declaration, we create a dictTable object based on the CustGroup table. We will use this object several times later in the code. Then we create a new form object and set its AOT name by calling the following code: The form should have a data source, so we add one by calling the addDataSource method on the form object and providing the previously created dictTable object.
The first thing to do is to add a strip action pane with its buttons: Just to follow best practice, we place the grid inside of a Group control: ColumnWidth ; grid. ColumnHeight ; Next, we add a number of grid controls pointing to the relevant data source fields by calling addDataField on the grid object.
The last thing is to initialize and run the form. Here we use a recommended approach to create and run forms using the globally available classFactory object. Adding a form splitter In Dynamics AX, more complex forms consist of one or more sections. Each section may contain grids, groups or any other element. In order to maintain section sizes while resizing the form, the sections are normally separated by so-called splitters. Splitters are not special Dynamics AX controls; they are group controls with the properties modified so they look like splitters.
Most of the multisection forms in Dynamics AX already contain splitters. In this recipe, to demonstrate the usage of splitters, we will modify one of the existing forms that does not have a splitter.
We will modify the Account reconciliation form in the Cash and bank management module, which can be opened from Cash and bank management Bank accounts list page, by clicking on the Reconcile Account reconciliation button in the action pane, and then selecting any of the existing records and hitting the Transactions button.
In the following screenshot, you can see that it is not possible to control the sizes of each grid individually, and they are resized automatically using a fixed ratio when resizing the form: We will add a form splitter in the middle of the two grids in the mentioned form.
It will allow users to define the size of both grids to make sure the data is optimally displayed. Open the BankReconciliation form in the AOT, and in the form's design add a new Group control right after the ActionPage control with the following properties: Move the AllReconciled, Balances, and Tab controls into the newly created group.
Add a new Group control right below the Top group with the following properties: Add the following line of code to the bottom of the form's class declaration: Add the following line of code to the bottom of the form's init method: Override three methods in the Splitter group with the following code: Change the following properties of the existing BankTransTypeGroup group: Property Height Value Column height 9. Now, to test the results, open Cash and bank management Bank accounts, select any bank account, click Reconcile Account reconciliation, choose an existing one or create a new bank statement, and click on the Transactions button.
Notice that the form now has a nice splitter in the middle, which makes the form look better and allows resizing of both grids: Normally, a splitter has to be placed between two form groups. In this recipe, to follow that rule, we need to adjust the BankReconciliation form's design.
We do not want this new group to be visible to the user, so we set FrameType to None.
Setting AutoDeclaration to Yes allows us to access this object from the code. Finally, we make this group automatically expanding in the horizontal direction by setting its Width to Column width.
At this stage, visual form layout does not change, but now we have the upper group ready. The BankTransTypeGroup group could be used as a bottom group with slight changes. We change its Top behavior to Auto and make it fully expandable in the horizontal and vertical directions. The Height of the grid inside this group also has to be changed to Column height in order to fill all the vertical space.
In the middle of those two groups, we add a splitter. The splitter is nothing but another group, which looks like a splitter.
This group does not hold any other controls inside, therefore, in order to make it visible we have to set the HideIfEmpty property to No. The Column width value of the property Width forces the splitter to automatically fill the form's width. After it has been declared in the form's class declaration, we instantiate it in the form's init method.
We pass the name of the splitter control, the name of the top group, and the form itself as arguments when creating it. A fully working splitter requires three mouse event handlers. It is implemented by overriding the mouseMove , mouseDown , and mouseUp event methods in the splitter group control.
In this way, horizontal splitters can easily be added to any form. Vertical splitters can also be added to forms using a very similar approach. Creating a modal form Quite often people who are not familiar with computers and software tend to get lost among open application windows. The same could be applied to Dynamics AX. Often a user opens one form, clicks a button to open another one, and then goes back to the first one without closing the second one.
Sometimes this happens intentionally, sometimes not, but the result is that the second form is hidden behind the first one and the user starts wondering why it is not possible to close or edit the first form. In other words, the second form always stays on top of the first one until closed. In this recipe, we will do exactly that. As an example, we will make the Create sales order form a modal window.
Property WindowType Value Popup 2. In order to test, open Sales and marketing Sales orders All sales orders, and start creating a new order. Notice that now the sales order creation form always stays on top: The design of the form has a WindowType property, which is set to Standard by default. In order to make a form behave as a modal window, we have to change it to Popup. Such forms will always stay on top of the parent form.
We already know that some of the Dynamics AX forms are created dynamically using the Dialog class. If we look deeper into the code, we could find that the Dialog class actually creates a runtime form. This means that we can apply the same principle—change the relevant form's design property. The following code could be added to the Dialog object and would do the job.
The format is given as follows: Popup ; Here we get a reference to the form's design, by first using the dialogForm method of the dialog object to get a reference to the DialogForm object, and then we call buildDesign on the latter object. Finally, we set the design property by calling its windowType with an argument FormWindowType:: Every runtime form inherits that class; therefore the class could be used to override some of the common behavior for all Dynamics AX forms.
For example, form background color could be changed depending on some parameters, some controls could be hidden or added depending on specific circumstances, and so on. ButtonGroup, 'ButtonGroup' ; btngrp. CommandButton, 'About' ; cmdAbout. EmbeddedResource ; cmdAbout. Yes ; cmdAbout. In the same class, override the run method with the following code: In order to test the results, open any list page, for example, Accounts receivable Customers All customers and look for the new button About Microsoft Dynamics AX in the action pane: SysSetupFormRun is the application class that is called by the system every time a user runs a form.
The best place to add our custom control is to override the run method. We use the this. If one of those conditions is not met, we stop the code, otherwise we continue by adding a new separate button group and the About Microsoft Dynamics AX command button.
Now every form in Dynamics AX with an action pane will have one more button. This feature is implemented across a number of standard forms, reports, periodic jobs, and other objects, which requires a user input. When developing a new functionality for Dynamics AX, it is recommended to keep it that way.
In this recipe, we will demonstrate how to save the latest user selections. In order to make it as simple as possible, we will use existing filters on the General journal form, which can be opened from General ledger Journals General journal.
This form contains two filters—Show and Show user-created only. The Show filter allows journals to be displayed by their posting status and the Show user-created only toggles between all journals and the currently logged in user's journals. CurrentVersion 1 localmacro. CurrentList showStatus, showCurrentUser endmacro 2. Create the following additional form methods: Add the following code to the form's run method right before its super: Add the following code to the bottom of the form's close method: Now to test the form, open General ledger Journals General journal, change the filter's values, close the form, and open it again.
The latest filter selections should stay: First of all, we define two variables, one for each filter control. We will store the journal posting status filter value in showStatus, and the current user filter value in showCurrentUser. The macro CurrentList is used to define a list of variables that we are going to save in the usage data. Currently, we have both variables inside it. The macro CurrentVersion defines a version of the saved values.
In other words, it says that the variables defined by the CurrentList, which will be stored in system usage data, can be addressed using the number 1. Normally, when implementing the last value saving for the first time for a particular object, CurrentVersion is set to 1. Later on, if we decide to add new values or change existing ones, we have to change the value of CurrentVersion, normally increasing it by 1.
This ensures that the system addresses the correct list of variables in the usage data and does not break existing functionality. The initParmDefault method specifies default values if nothing is found in the usage data. Normally, this happens if we run a form for the first time, we change CurrentVersion or clean the usage data.
This method is automatically called by the xSysLastValue class. In our case, pack returns a container consisting of three values: These values will be sent to the system usage data storage after the form is closed. During an opening of the form, the xSysLastValue class uses unpack to extract values from the stored container. It checks whether the container version in the usage data matches the current version number, and only then the values are considered correct and are assigned to the form variables.
This ensures that different users can store last values for different objects without overriding each other's values in the usage data. The lastValueDesignName method is meant to return the name of the object's current design in cases where the object can have several designs. In this recipe, there is only one design, so instead of leaving it empty, we used it for a slightly different purpose. The same LedgerJournalTable form can be opened from various menu places.
For example, the form could be presented to the user as General journal, Periodic journals or Payment journal forms.
In order to ensure that the user's latest choices are saved correctly, we include the caller menu item name as part of the unique string. The last two pieces of code need to be added to the form's run and close methods. In the run method, xSysLastValue:: The next two lines assign the values to the respective form controls.
Finally, code lines in the close method are responsible for assigning user selections to the variables and saving them to the usage data by calling xSysLastValue:: Using a tree control Frequent users should notice that some of the Dynamics AX forms use tree controls instead of commonly used grids. In some cases, it is extremely useful, especially when there are parent-child relationships among records.
It is a much clearer way to show the whole hierarchy compared to a flat list. For example, projects and their subprojects are displayed in the Projects form of the Project management and accounting module and give a much better overview when displayed in a tree layout. This recipe will discuss the principles of how to build tree-based forms.
As an example, we will use the Budget model form, which can be found in Budgeting Setup Budget models. This form contains a list of budget models and their submodels, and although the data is organized using a parent-child structure it is still displayed as a grid. In this recipe, to demonstrate the usage of tree controls, we will replace the grid with a new tree control.
Heading notExists join submodel where submodel. Root, model. ModelId, model. Property Visible Value No 3. Create a new Tree control right below the BudgetModel grid with the following properties: Add the following code to the bottom of the form's class declaration: BudgetModelTree modelTree; 5.
Add the following code to the bottom of form's init: Override selectionChanged on the Tree control with the following code: SubModelId; 88 Chapter 2 select firstOnly model where model. Override the delete method on the BudgetModel data source with the following code: Override the delete method on the SubModel data source with the following code: Add the following code to the bottom of the write method on the BudgetModel data source: Override the write method on the SubModel data source and add the following code to its bottom: To test the tree control, open Budgeting Setup Budget models.
Notice how the ledger budget models are presented as a hierarchy: This recipe contains a lot of code, so according to best practice we create a class to hold most of it. This allows us to reuse the code and keep the form less cluttered. The new class contains a few common methods like new and construct for initializing the class and two methods, which actually generate the tree.
The first method is createNode and is used for creating a single budget model node with its children, if any. It is a recursive method, and it calls itself to generate the children of the current node. It accepts a parent node and a budget model as arguments. The rest of the code loops through all submodels and creates subnodes if there are any for each of them.
Secondly, we create the buildTree method where the whole tree is created. Before we start building the tree, we delete all nodes and lock the tree control. Then, we add nodes by looping through all parent budget models and calling the previously mentioned createNode.
We call the expandTree of the SysFormTreeControl class to display every parent budget model initially expanded. Once the hierarchy is ready, we unlock the tree control. Next, we modify the BudgetModel form by hiding the existing grid section and adding a new tree control. Tree nodes are always generated from the code, and the class mentioned above will do exactly that. On the form, we declare and initialize the modelTree object and build the tree in the form's init.
In order to ensure that the currently selected tree node is displayed on the form on the right, we override the tree control's selectionChanged event which is triggered every time a tree node is selected. Here we locate a corresponding record and place a cursor on that record.
The rest of the code on the form is to ensure that the tree is rebuilt whenever the data is modified. In this section we will discuss how to improve tree control's performance and how to enable its drag-and-drop functionality.
Performance Tree hierarchy generation might be time consuming, so for bigger trees it is not beneficial to build the whole tree initially. This could be achieved by placing the relevant code into the expanding method of the tree control which represents an event when a tree node is being expanded.
Such an approach ensures that no system resources are used on generating unused tree nodes. This makes daily operations much quicker and more effective. Let's modify the previous example to support drag-and-drop. We are going to allow the users to move ledger budget submodels to different parents within the tree. In order to do that, we need to make some changes to the BudgetModelTree class and the BudgetModel form.
Add the following code to the BudgetModelTree class declaration: SubModel; return model. ModelId; if modelFrom. It enables the drag-and-drop functionality in the tree, once we set its value to Manual. The next step is to override the drag-and-drop events on the tree control. Trees can have a number of methods covering various drag-and-drop events.
In this example, we will cover only three of them: Here, we normally store the number of the item that is being dragged for later processing.
This method is responsible for highlighting nodes when the dragged item is over them. Its return value defines the mouse cursor icon once the item is being dragged.
Here, we normally place the code that does actual data modifications. In this example, all logic is stored in the BudgetModelTree class.
Each of the mentioned form methods call the corresponding method in the class. This is to reduce the amount of code placed on the form and allow the code to be reused on multiple forms. We added the following methods to the class: Although there might be more conditions, for this demonstration we only disallow dragging of top nodes.
Using stateDropHilited , we highlight the current item and we remove highlighting from the previously highlighted one. This ensures that as we move the dragged item over the tree, items are highlighted once the dragged item is over them and the highlight is removed once the dragged item leaves them. This method is called later from several places to make sure node highlighting works correctly.
If not, then it returns FormDrag:: None, which changes the mouse cursor to the forbidden sign. Otherwise, the cursor is changed to an icon representing node movement. This method also calls stateDropHilite to ensure correct node highlighting. If yes, then it uses move to update the data and moveItem to visually change the node's place in the tree. It also calls stateDropHilite to update tree node highlighting. Normally, a checklist is a list of menu items displayed in a logical sequence.
Each item represents either mandatory or optional action 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 consist of two mandatory items and one optional item. Create three classes, one for each checklist item, with the following code: TopicId 'Dynamics: Create another class for the checklist itself, with the following code: In the AOT, create a new action menu item with the following properties: The following should appear on the right-hand side of the Dynamics AX window: Click on the listed items to start and complete the relevant actions.
Notice how the status icons change upon completion of each task. The main principle when creating the checklist is that we have to create a main class, which represents the checklist itself, and a number of checklist item classes representing each item in the checklist. 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. Next, we implement the interface in three SysCheckListItem classes, which correspond to Models, Codes, and Budget register entries 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: In this example, we use placeAfter to determine the position of the item in the list relative to other items, indeterminate to make an item optional and addDependency to make an item inactive until another specified item is completed. The budget checklist has two groups, Setup and Create budgets.
Here, we have Budget models, Budget codes, and Budget register entries menu items, respectively, in each class. Next we override some of the methods to add custom functionality to the checklist: In this example, we store each status in the local variable log to make sure that each status is reset every time we run the checklist.
The display menu item we have created points 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: 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 class. Suggested Answer. Hi, If you do a basic search, you'l find a lot of tutorials, Microsoft Learning Materials, etc.
Chaitanya Golla responded on 17 Oct Getting Started sumitax. Sandeep Kommineni responded on 17 Oct Regards, Sandeep Kommineni. Hi, You are welcome. Please mark verified those answers which are useful for you.
Vilmos Kintera responded on 18 Oct 3: