Multi Select lookup on a Data Source filed control in D365 fo X++

Implementing a Multi-Select Lookup Control in D365FO

Overview

In this document, we’ll walk through how to implement a custom multi-select lookup in a Dynamics 365 Finance and Operations form. Our scenario will use Purchase Requisition Header as an example, where a user needs to select multiple Department values.

We'll leverage the SysLookupMultiSelectCtrl class for this implementation.

What is SysLookupMultiSelectCtrl?

SysLookupMultiSelectCtrl is a system class in D365FO used to create multi-select lookups on form controls. It provides three static methods to construct the control:

  • SysLookupMultiSelectCtrl::construct() — uses an AOT query name.

  • SysLookupMultiSelectCtrl::constructWithQuery() — uses a Query object.

  • SysLookupMultiSelectCtrl::constructWithQueryRun() — uses a QueryRun object.

Implementation Steps

1. Add Custom Field

Create a new field in the PurchReqTable table named DaxDepartment.









2. Add the Field to the Form

Add the newly created DaxDepartment field to the PurchReqTable form.







3. Extend the PurchReqTable Form

Create a CoC (Chain of Command) extension for the PurchReqTable form and add the following logic:

x++

[ExtensionOf(formStr(PurchReqTable))]
final class PurchReqTable_DaxExtensions_Extension
{
    public SysLookupMultiSelectCtrl msCtrl;
    public Query qry;

    public Query buildDeptQuery()
    {
        Query query = new Query();
        QueryBuildDataSource qbds;

        qbds = query.addDataSource(tableNum(OMOperatingUnit));
        qbds.addSortField(fieldNum(OMOperatingUnit, OMOperatingUnitNumber));
        qbds.addSelectionField(fieldNum(OMOperatingUnit, OMOperatingUnitNumber));
        qbds.addSelectionField(fieldNum(OMOperatingUnit, Name));
        qbds.addRange(fieldNum(OMOperatingUnit, OMOperatingUnitType)).value(int2str(OMOperatingUnitType::OMDepartment));

        return query;
    }

    public SysLookupMultiSelectCtrl parmSysLookupMultiSelectCtrl(SysLookupMultiSelectCtrl _msCtrl = msCtrl)
    {
        msCtrl = _msCtrl;
        return msCtrl;
    }

    public container DaxGetselectedValues(str _noteStr)
    {
        container recordIds, deptIds;
        OMOperatingUnit omOperatingUnit;
        List deptList = Global::strSplit(_noteStr, ";");
        ListEnumerator deptListEnumerator = deptList.getEnumerator();

        msCtrl.refreshQuery(qry);

        while (deptListEnumerator.moveNext())
        {
            select firstOnly omOperatingUnit
                where omOperatingUnit.OMOperatingUnitNumber == deptListEnumerator.current();

            RecId recordId = omOperatingUnit.RecId;

            if (recordId)
            {
                recordIds += recordId;
                deptIds += deptListEnumerator.current();
            }
        }

        return [recordIds, deptIds];
    }

    public void init()
    {
        FormStringControl department;
        PurchReqTable purchReqTable;

        next init();
        qry = this.buildDeptQuery();
        department = this.design().controlName('PurchReqTable_DaxDepartment');
        purchReqTable = this.dataSource(formDataSourceStr(PurchReqTable, PurchReqTable)).cursor() as PurchReqTable;

        if (!msCtrl)
        {
            msCtrl = SysLookupMultiSelectCtrl::constructWithQuery(this, department, qry);
        }
        else
        {
            msCtrl.refreshQuery(qry);
        }

        this.parmSysLookupMultiSelectCtrl(msCtrl);
    }
}

4. Extend the Form Data Source — active() Method

Create a data source extension for PurchReqTable and override the active() method to populate the lookup with previously selected values:

x++

[ExtensionOf(formDataSourceStr(PurchReqTable, PurchReqTable))] public final class DaxPurchReqTable_FormDs_Extension { public int active() { int ret; PurchReqTable purchReqTable; SysLookupMultiSelectCtrl msCtrlloc = element.msCtrl; FormDataSource purchReqTableDs = this; FormRun formRun = purchReqTableDs.formRun(); purchReqTable = purchReqTableDs.cursor(); ret = next active(); msCtrlloc.set(formRun.DaxGetselectedValues(purchReqTable.DaxDepartment)); element.msCtrl = msCtrlloc; return ret; } }


5. Add Logic in the OnModified Event

Handle the Modified event on the field control to store the selected values:

x++

[FormDataFieldEventHandler(formDataFieldStr(PurchReqTable, PurchReqTable, DaxDepartment), FormDataFieldEventType::Modified)] public static void DaxDepartment_OnModified(FormDataObject sender, FormDataFieldEventArgs e) { FormRun formRun = sender.dataSource().formRun(); SysLookupMultiSelectCtrl msCtrlloc = formRun.parmSysLookupMultiSelectCtrl(); FormStringControl department = formRun.design().controlName('PurchReqTable_DaxDepartment'); PurchReqTable purchReqTable = formRun.dataSource(formDataSourceStr(PurchReqTable, PurchReqTable)).cursor() as PurchReqTable; purchReqTable.DaxDepartment = con2Str(msCtrlloc.getSelectedFieldValues(), ';'); }



UI Testing

Once implemented, build and synchronize the project. Then navigate to the Purchase Requisition form and test the DaxDepartment field. You should see a multi-select lookup that allows choosing multiple department values.













Conclusion

You've now successfully implemented a multi-select lookup control on a D365FO form using SysLookupMultiSelectCtrl. This dynamic and user-friendly approach enhances flexibility and usability within your business application.


Thanks,

Thiru. G


No comments:

Post a Comment