We are getting ready to say goodbye to the Dynamics 365 for Operations Help Wiki. We're moving to https://docs.microsoft.com/dynamics365/operations. We'll start redirecting you to topics on the new site at the end of April. We will be disabling editing and comments at the same time.

    Extend the RunBase class

    This topic contains an example that shows how a RunBase class can be augmented end to end.

    When you extend functionality of the application suite, you will encounter classes that extend the RunBase class. This topic shows how a RunBase class can be augmented end to end.

    For example, you want to extend the SysUserLogCleanup class. Out of the box, this class can delete records from the SysUserLog table. However, you want to archive these records to a different table before they are deleted.

    The SysUserLogCleanup class is a RunBase class. The RunBase class has a dialog box, where the user is prompted for parameters before the class is run. For this example, we will add a toggle button control to the dialog box, get the value of the control, act on the value in the run method, and make sure that the value is serialized via the pack and unpack methods. Serialization helps guarantee that the user’s last selection is presented again if the dialog box is reopened. It also helps guarantee that the settings are applied if the class is run in the background.

    To avoid collisions with other eventual extensions, we followed these best practices:

    • Prefix members and methods. In the example, the prefix “my” is used. This practice is important, because it helps prevent name clashes with other extensions and future versions of the augmented class.
    • Use RunBase.packExtension() and RunBase.unpackExtension(). These methods provide serialization in a nonintrusive manner. They enable serialization of multiple extensions of the same class. The methods are available starting in Platform Update 5.

    The following example shows how to implement this scenario.

    [ExtensionOf(classStr(SysUserLogCleanup))]
    final class MySysUserLogCleanup_Extension
    {
        // static members
        static private SysUserLogCleanup myRunningInstance;
    
        // Extending class state...
        private boolean myArchive;
        private DialogField myDialogArchive;
        #define.CurrentVersion(1)
        #localmacro.CurrentList
            myArchive
        #endmacro
    
        // Adding new instance methods
        private void myDialog(Dialog _dialog)
        {
            myDialogArchive = _dialog.addField(extendedtypestr(NoYesId), "Archive");
            myDialogArchive.value(myArchive);
        }
        private void myGetFromDialog()
        {
            myArchive = myDialogArchive.value();
        }
        private boolean myUnpack(container packedClass)
        {
            Integer version = RunBase::getVersion(packedClass);
            switch (version)
            {
                case #CurrentVersion:
                    [version, #currentList] = packedClass;
                    break;
                default:
                    return false;
            }
            return true;
        }
        private container myPack()
        {
            return [#CurrentVersion, #CurrentList];
        }
        private void myInitParmDefault()
        {
            myArchive = true;
        }
        private void myArchiveUserLog(SysUserLog _userLog)
        {
            if (myArchive)
            {
                //...
            }
        }
    
        // Wiring up event handlers...
        [PostHandlerFor(classStr(SysUserLogCleanup), methodStr(SysUserLogCleanup, dialog))]
        public static void SysUserLogCleanup_Post_Dialog(XppPrePostArgs _args)
        {
            Dialog dialog = _args.getReturnValue();
            SysUserLogCleanup instance = _args.getThis() as SysUserLogCleanup;
            instance.myDialog(dialog);
        }
        [PostHandlerFor(classStr(SysUserLogCleanup), methodStr(SysUserLogCleanup, getFromDialog))]
        public static void SysUserLogCleanup_Post_GetFromDialog(XppPrePostArgs _args)
        {
            SysUserLogCleanup instance = _args.getThis() as SysUserLogCleanup;
            instance.myGetFromDialog();
        }
        [PostHandlerFor(classStr(SysUserLogCleanup), methodStr(SysUserLogCleanup, pack))]
        public static void SysUserLogCleanup_Post_pack(XppPrePostArgs _args)
        {
            SysUserLogCleanup instance = _args.getThis() as SysUserLogCleanup;
            //Also pack the extension
            instance.packExtension(_args, classStr(MySysUserLogCleanup_Extension), instance.myPack());
        }
        [PostHandlerFor(classStr(SysUserLogCleanup), methodStr(SysUserLogCleanup, unpack))]
        public static void SysUserLogCleanup_Post_unpack(XppPrePostArgs _args)
        {
            SysUserLogCleanup instance = _args.getThis() as SysUserLogCleanup;
            container myState = instance.unpackExtension(_args, classStr(MySysUserLogCleanup_Extension));
            //Also unpack the extension
            if (!instance.myUnpack(myState))
            {
                //Extension couldn't be unpacked - return false to trigger initParmDefault() gets called
                _args.setReturnValue(false);
            }
        }
        [PostHandlerFor(classStr(SysUserLogCleanup), methodStr(SysUserLogCleanup, initParmDefault))]
        public static void SysUserLogCleanup_Post_initParmDefault(XppPrePostArgs _args)
        {
            SysUserLogCleanup instance = _args.getThis() as SysUserLogCleanup;
            instance.myInitParmDefault();
        }
        [PreHandlerFor(classStr(SysUserLogCleanup), methodStr(SysUserLogCleanup, run))]
        public static void SysUserLogCleanup_Pre_run(XppPrePostArgs _args)
        {
            //Store a static reference, so we can call it from SysUserLog_onDeleting.
            myRunningInstance = _args.getThis() as SysUserLogCleanup;
        }
        [PostHandlerFor(classStr(SysUserLogCleanup), methodStr(SysUserLogCleanup, run))]
        public static void SysUserLogCleanup_Post_run(XppPrePostArgs _args)
        {
            //Running complete 
            myRunningInstance = null;
        }
    
        // Wiring up event handler for deletion of the record
        [DataEventHandler(tableStr(SysUserLog), DataEventType::Deleting)]
        static public void SysUserLog_onDeleting(Common _sender, DataEventArgs _e)
        {
            if (runningInstance)
            {
                myRunningInstance.myArchiveUserLog(_sender as SysUserLog);
            }
        }
    }
    Rate this article

    Report inappropriate content

    Contribute to a discussion

    Comments are disabled for this Wiki.