Pages

Saturday, June 8, 2013

Execute Menu Items through code

I've seen some people trying to find out how to execute or run Menu Items programatically on the internet.

So I thought I'd best blog about it.

We have three types of Menu Items: Action, Output and Display.

An action is frequently a class that performs some business operation, an output is a report and a display is a form.

Menu Items are represented by the MenuFunction class. Here's some code example to run Menu Items through code:

MenuFunction menuFunction;

menuFunction = new MenuFunction(menuItemDisplayStr(MyDisplayMenuItem), MenuItemType::Display);
menuFunction.run();

Of course the code above may be changed to execute different kinds of Menu Items, for example, the code below runs an Output Menu Item:

MenuFunction menuFunction;

menuFunction = new MenuFunction(menuItemOutputStr(MyOutputMenuItem), MenuItemType::Output);
menuFunction.run();

And if you need to pass any arguments to the Menu Item you're trying to execute, you can pass it with an Args object. The run method accepts an Args parameter, like this:

Args args = new Args();

args.record(myArgumentRecord);

args.caller(this);

new MenuFunction(menuItemOutputStr(MyOutputMenuItem), MenuItemType::Output).run(args);

You should always use functions to get the name of the menu item instead of using a hardcoded string. This guarantees that if someone changes the name of the menu item, your code stops compiling and you have time to fix it before shipping it. The following are the three functions used to get the menu items' name. Their names are pretty straightforward:


Here's a link to a Stack Overflow question that I answered but didn't get the answer :(.

Friday, June 7, 2013

Dynamics AX Custom Reference Group Lookup

Microsoft Dynamics AX 2012 introduced a new form control type: the reference group.

And also, very often we'll have to customize the contents of the lookup, or filter them. We can do this by using the SysReferenceTableLookup class.


So go to your form's data source and find the reference field for which you want to perform the lookup. Override its lookupReference method.

The use of the SysReferenceTableLookup is very similar to the SysTableLookup: we construct a Query, add data sources and ranges to it, and then pass it to the SysReferenceTableLookup object, like the code below:


public Common lookupReference(FormReferenceControl _formReferenceControl)
{
    SysReferenceTableLookup     sysRefTableLookup;
    Query                       lookupQuery = new Query();
    QueryBuildDataSource        lookupQueryDataSource;

    // Construct the SysRefTableLookup object
    sysRefTableLookup = SysReferenceTableLookup::newParameters(tableNum(MyTable), _formReferenceControl)

    // Add the field list that will be displayed on the lookup form
    sysRefTableLookup.addLookupfield(fieldNum(MyTable, MyFirstField));
    sysRefTableLookup.addLookupfield(fieldNum(MyTable, MySecondField));

    // Construct the query's data source
    lookupQueryDataSource = lookupQuery.addDataSource(tableNum(MyTable));

    // Add ranges to the query data source
    lookupQueryDataSource.addRange(fieldNum(MyTable, MyFirstField)).value(queryValue('Foo'));
    lookupQueryDataSource.addRange(fieldNum(MyTable, MySecondField)).value(queryNotValue(''));

    // Pass the query to the lookup object
    sysRefTableLookup.parmQuery(lookupQuery);

    return sysRefTableLookup.performFormLookup();
}


Unlike the SysTableLookup, the SysReferenceTableLookup returns an object of type Common which is the record the user selected on the lookup.

For this example I created the lookup logic directly on the form, but you could always create a lookup method directly on your table, and then make the control's lookup method call the table one. It's entirely up to you.

Just don't forget to validate the user input, because filtering the lookup does not stop the user from typing in a value on the control instead of selecting the record on the lookup. You could do it by overriding the control's validate method or directly on the table with the validateField method.

Monday, June 3, 2013

Get selected records on the grid / datasource

This should also be a common task for Dynamics AX developers.

Fortunately, there's a little helper class in AX to make it easier for us, the MultiSelectionHelper.


For example, if you want to get a set of selected records in a grid, you could use it like this:

MyTableBuffer            myTableBuffer;
MultiSelectionHelper     selectionHelper = MultiSelectionHelper::construct();
Set                      selectedRecords = new Set(Types::Record);


selectionHelper.parmDataSource(myTableBuffer_DS);

myTableBuffer = selectionHelper.getFirst();

while (myTableBuffer)
{
    selectedRecords.add(myTableBuffer);

    myTableBuffer = selectionHelper.getNext();
}


The code above should be very useful when getting the list of selected records directly on the form, but if you want to get the selected records in a class that was called from a form, for example, you could use the MultiSelectionHelper like this:

public static void main(Args _args)
{    
    FormDataSource          formDataSource;    
    MyTableBuffer           myTableBuffer;
    FormRun                 caller = _args.caller();
    MultiSelectionHelper    helper = MultiSelectionHelper::createFromCaller(caller);
    Counter                 i;

    // First we need to get the correct form data source
    for (i = 1; i <= caller.dataSourceCount(); i++)
    {
        formDataSource = caller.dataSource(i);

        if (formDataSource.table() == tableNum(MyTableBuffer))
        {
            break;
        }
    }

    // We then tell the selection helper object to create ranges for the selected records
    helper.createQueryRanges(formDataSource.queryBuildDataSource(), fieldStr(MyTableBuffer, RecId));

    // Now we can traverse the selected records
    myTableBuffer = helper.getFirst();

    while (myTableBuffer)
    {
        info(myTableBuffer.RecId);

        myTableBuffer= helper.getNext();
    }
}
In the example above we received the caller form with the _args object. Then, we have to find the correct FormDataSource object. This should be the table for which we want to get the list of records. After getting the correct data source, we can then tell the selection helper object to create ranges for the selected records on the specified QueryBuildDataSource, which we can now get directly from the FormDataSource in Dynamics AX 2012, with the queryBuildDataSource method. And the last part is the same as the first code example, only this time I didn't add the selected records to a set, I just showed their RecId on the Infolog. Since we need to get the FormDataSource for this latter approach, we can only use it if our form only has one data source for the table we're trying to get.

This should be very useful when you need to perform certain action on a list of selected records. Hope it helps.