Dynamics AX 2012 R2 : XppPrePostArgs changes

Amongst many other changes made in Microsoft Dynamics AX 2012 R2, there has been soms changed to the XppPrePostArgs class too. But before you even read further, please also have a good read through a series of posts made by Joris Degruyter. The series give a nice overview of using models and events to make you code more upgradable. If there was a bible written for AX, this would be one of the first commandments!

In the series of post, Joris explains the use of the XppPrePostArgs class to fetch arguments you want to use in your event handler class. To get the FieldId from the args when the validateField method was triggered, the following code was used:

if(_args.getArg(_args.args().fieldName(1)) == FieldNum(CustTable, DMProjId)

Well, since R2, the XppPrePostArgs class has been modified to extend object instead of XppEventArgs. (MSDN: http://msdn.microsoft.com/en-us/library/xppprepostargs.aspx)
One of the concequences is the absence of the args() method. So when you want to do the same thing as above, you now have to use the following code (it’s a bit simplified and less ugly) :

if(_args.getArgNum(1) == FieldNum(CustTable, DMProjId)

 

Event Handling in X++

When you are writing code in C# you can create events and define delegate methods that will be called when the event is triggered. Unfortunately, this is not implemented in the X++ language.

I have read some nice posts about how eventing is implemented in .NET and about the design patterns used (observer, …) and decided to build this myself.

The method I used is using the observer pattern and lets you subscribe to an eventhandler object that can be defined on a class you want to monitor. It is actually quite simple, but can come in handy when available.

Note : Don’t mind the HEL prefix, this is just a prefix used for some tools here. And also, some objects can be extended with additional functionality to contain more information, …

First I created an HELEventHandler class which contains a map with registered listener objects. The methods attachListener and removeListener can be used to register / deregister an object method to listen for the event. The validateListener performs some checks to see if the callback method has the right structure. The fireEvent method is responsible to notify all the listeners of the event triggered.

The HELEventArguments class is created just to pass it when the event is fired. For now, this is an empty shell, but can be extended / adjusted to contain extra information on the fired event.

Now let’s see how we can put this to work. First we start by create a class for testing: HELTestClassEvent. We have a name member here and an eventhandler member.

class HELTestClassEvent
{
    Name mName;
    HELIEventHandler mNameChangedEventHandler;
}

The eventhandler is made public by adding a parameter method.

public HELIEventHandler parmNameChangedEventHandler(HELIEventHandler _nameChangedEventHandler = mNameChangedEventHandler)
{
    ;
    mNameChangedEventHandler = _nameChangedEventHandler;
    return mNameChangedEventHandler;
}

Now let’s say we want an event that is triggered when the name changes. Then we would like to add a method that can be called to notify that the name has changed.

private void onNameChanged(Object _sender, HELEventArguments _arguments)
{
    ;
    if(this.parmNameChangedEventHandler())
    {
        this.parmNameChangedEventHandler().fireEvent(_sender, _arguments);
    }
}

And this will be called like this :

void run()
{
    ;
    mName = "Kenny";

    this.onNameChanged(this, new HELEventArguments());

    info("I did my work");
}

For now, we have everything we need to let an object notify others that an event has happened. Now we will take a look at how we can register other objects to listen to this event. Let’s create an extra class that will be notified. There, we will first need to create a method that will do the actual work when the event is fired.

public void HELTestClassEvent_OnNameChanged(Object _sender, HELEventArguments _eventArgs)
{
    ;
    info("Who changed the name ?!");
}

And last but not least we actually attach this method to the event by doing this:

void run()
{
    HELTestClassEvent test = HELTestClassEvent::construct();
    ;

    // We want to attach a method of this class to the event that the name is changed in the HELTestClassEvent object
    test.parmNameChangedEventHandler(HELEventHandler::construct());
    test.parmNameChangedEventHandler().attachListener(this, methodStr(HELTestClassEventCalledBack, HELTestClassEvent_OnNameChanged));

    // Run the HELTestClassEvent object
    test.run();
}

The source can be found here