Skip to main content

Args and the Axapta Construction Pattern

When looking through Axapta code you will see a lot of references to the type Args. This type is used as a general method for sharing construction parameters. It works well because in the Axapta usage pattern because


1.the typical number of parameters is small
2.the types of parameters used is very similar
3.construction of the main objects often entails constructing multiple collaborating objects that need access to the same shared constructor arguments.

In traditional OO code each object will have one or more constructors. These constructors would have different numbers of arguments and types, as required. For example, a class representing a form might have a default constructor that would simply show all the items in the table. It could also have a constructor that accepted a string that was used to highlight the row with a matching primary key, newSelect(str key). Or one that filtered all the values to match the provided range, newMinMax(str smin, str smax). Side note: in Axapta there is no overloading, we accomplish the same thing with multiple static constructor methods. They are typically named newXyz, newAbc, etc. Sometimes the create prefix is used, for example createXyz, createAbc.



This works well in the simple case, however if a class needs to construct many collaborating objects each requiring the same specialized constructors, the process becomes unwieldy. In addition, the construction is often handled indirectly. That is, there is some logic used to determine which constructor to use and the results of these decisions must pass through multiple layers. Also, as it turns out in Axapta the variety of startup parameters is remarkable similar for report, forms, action classes and other objects. The solution chosen by Axapta is to have a single constructor that takes an Args parameter. This single parameter packages up the most commonly used parameters.



This transforms the traditional OO multiple constructors (like this)




final class FormRun extends ObjectRun

{

static MyForm newSelect(str key)

{ ...new up a form with row selected ...}



static MyForm newRange(str smin, str smax)

{ ...new up a form with only range visible ...}

}



Into the he Axapta Args constructor pattern, which would look like this:




final class FormRun extends ObjectRun

{

public void new(Args _args)

{

if (something in _args)

{ ...new up a form with row selected ...}

if (something else in _args)

{ ...new up a form with only range visible ...}



}

}



The work is simply moved for a multiple static constructors to multiple if-else blocks. Note that most forms and reports do the work in the init() method instead of an overloaded new. The effect is the same. When you consider that many forms/reports have at least one helper class (often with the same name) and the sub‑elements (sections, queries, controls) that may also need to modify their behavior based on the startup parameters you can see that passing a single Args around is much easier. You don’t even have to pass the Args around if the object inherits from ObjectRun (which all forms and reports do), since ObjectRun holds the initial constructor Args. The pattern would break down if the number and type of parameters were vastly different.



Classes and jobs also use the Args pattern. Classes that are the target of an Action menu item will have a static main method that accepts a single Args parameter. By default jobs will also receive a single Args parameter.



Generic Args Properties:




Property


Type


Description




caller


object


A reference to the object that created the Args.




dataset


tableId


The table that lookupField and record refer too. However, this is often left null since the proper dataset is implied.




designName


str


Which of the designs within a report should be used, null implies the default design.




lookupField


fieldId


When showing a form, the field to filter on.




lookupValue


str


When showing a form, the value to filter with.




menuItemName


str


The name of the menu item that caused the object to be created.




menuItemType


menuItemType


The type of the menu item that caused the object to be created.




name


str


For reports and forms this is the name of menu item that invoked the form/report




parentWnd


int


I have only seen this used internally in the kernel to insure dialogs child windows are properly nested.




parm


str


A generic string property.




parmEnum


int


One of the values from the base enum specified by parmEnumType. Works together with the parmEnumType to select different behaviors.




parmEnumType


int


The id of the base enum. Typically you would use the enumnum(some-type) function.




parmObject


object


A generic object property.




record


common


A blank record for dataset. You can create a blank record with the DictTable. makeRecord() method. Often the lookupField is filled in with the lookupValue.




An interesting example on using Args to launch a form/report is in the \Classes\ClassFactory\drillDown method.




public void drillDown(OutputField _outputField, MenuItemType _menuItemType, str _menuItemName)

{

Args args = new Args();

MenuFunction menuFunction = new MenuFunction(_menuItemName, _menuItemType);

DictTable dt = new DictTable(_outputField.tableHandle());

Common record = dt.makeRecord();

sysReportRun sysReportRun;

FormRun formRun;

;

args.caller(null);

record.(_outputField.fieldHandle()) = _outputField.formatValue();

args.record(record);

args.name(menuFunction.object());

args.lookupField(_outputField.fieldHandle());

args.lookupValue(_outputField.formatValue());

...SNIP...

}



An example of a form taking different actions based on the enumeration parameter can be seen in the PriceDiscGroup form:




void init()

{

InventTableModule inventTableModule;

;

super();

if (element.args().parmEnumType())

{

module = element.args().parmEnum();

}

...SNIP...

}



An example of a class preparing some enumeration args for a form to consume can be found in the ProdJournalCreateBOM class:




client static void main(Args args)

{

...SNIP...

if (journalId)

{

argsTable = new Args();

argsTable.name(formstr(ProdJournalTable));

argsTable.parmEnumType(enumnum(ProdJournalType));

argsTable.parmEnum(ProdJournalType::Picklist);



...SNIP...

}

thanks David Ferguson

Popular posts from this blog

What does this mean: "The form datasource query object does not support changing its AllowCrossCompany property after the form has executed the query."?

I have made a form with datasources vendtable and vendtrans. Inside vendtable_ds.executequery() looks like this: QueryBuildDataSource queryBuildDatasource ,queryBDS_VendTrans_Invoice; ; queryBuildDatasource = this.query().dataSourceTable(tablenum(vendtable)); queryBDS_VendTrans_Invoice = this.query().dataSourceTable(tablenum(vendtrans)); if (curext() == "MASTERCOMP") { this.query().allowCrossCompany(true); } else { this.query().allowCrossCompany(false); } //FilterVendorName = stringedit control on form if (FilterVendorName.text()) { queryBuildDatasource.addRange(fieldNum(VendTable,Name)).value(strfmt("*%1*", FilterVendorName.text())); } else { queryBuildDatasource.clearRange(fieldNum(VendTable,Name)); } //FilterInvoiceNumber = stringedit control on form if (FilterInvoiceNumber.valueStr() == "") { queryBDS_VendTrans_Invoice.enabled(false); } else { queryBDS_VendTrans_Invoice.enabled(true); queryBDS_VendTrans_In...

Credit Note [Dynamics AX] using X++

This post will help to create credit note for a sales order based on the invent lot id. All the invoices raised for a particular sales line – Lot Id will be raised back as a credit note. Information on Credit Note: A credit note or credit memorandum (memo) is a commercial document issued by a seller to a buyer. The seller usually issues a Credit Memo for the same or lower amount than the invoice, and then repays the money to the buyer or sets it off against a balance due from other transactions Below Code will help to create credit note for all the invoices raised against the sales line -lot id. Please note: This code can be customized as per your requirements. This is just a template to help creating credit note using X++ code. Please test the code before use. static void SR_CreateCreditNote_Sales(Args _args) { // Coded by Sreenath Reddy CustInvoiceTrans custInvoiceTrans; Dialog dialog = new Dialog(“Create credit note – for sales.”); DialogField dfInv...