Create pre-event and post-event handler classes

Completed

You can use event handler classes for pre-handlers and post-handlers to extend an application, like how you’d use Chain of Command (CoC) for method wrapping.

An event handler class is another way to extend an application, and you use it as you would other event handler classes. You can use pre-handlers and post-handlers in a class where the original method has a pre-handler that runs before the original method and a post-handler that you would implement afterward. Handlers surround the original method. Additionally, you can use attributes to prevent or allow extending pre-handlers and post-handlers.

Pre-event and post-event classes

To add a pre-event and post-event class, create a new event handler class. You can add a class to a project from the Solution Explorer window by right clicking the project or activating the context menu and then selecting Add, New item, Code, Class or Add Class.

Enter a descriptive name for the pre-event and post-event class, such as CustTableTableEventHandler. It’s best practice to use the object name as a starting point, such as CustTable, and then add the object type, such as Table, because CustTable could be a table or a form. Then, you can append it with EventHandler. For example, you could have two event handler classes that are named CustTableTableEventHandler and CustTableFormEventHandler.

To add a pre-event or post-event, make sure that the method that’s in the event handler class is discoverable. On the method, right-click or activate the context menu, select Copy event handler method, and then select Pre-event handler, as the following image depicts.

Visual Studio screenshot showing how to copy event handler method from
and then select Pre-event handler.

After you select the pre-event handler, go to the event handler class, and then paste the method. Return to the method, select the post-event handler, and then paste it in the event handler class.

Two methods for pre-events and post-events should display, and the original method is called between these two methods (super call), as the following code sample illustrates:

internal final class CustTableTableEventHandler
{
    /// <summary>
    ///
    /// </summary>
    /// <param name="args"></param>
    [PreHandlerFor(tableStr(CustTable), tableMethodStr(CustTable, insert))]
    public static void CustTable_Pre_delete(XppPrePostArgs args)
    {
        CustTable custTable = args.getThis() as CustTable;

        // do something
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="args"></param>
    [PostHandlerFor(tableStr(CustTable), tableMethodStr(CustTable, insert))]
    public static void CustTable_Post_delete(XppPrePostArgs args)
    {
        CustTable custTable = args.getThis() as CustTable;

        // do something
    }
}

Attributes

You can add attributes to a method to prevent people from using pre-handlers and post-handlers and other extensions. The three types of attributes that you can add are hookable, wrappable, and replaceable.

Hookable attributes complete the following actions:

  • [Hookable(false)] - Overrides the behavior so that it’s not possible to create pre-events and post-events, which means that the method isn’t wrappable.
  • [Hookable(true)] - Overrides the behavior so that it’s possible to create pre-events and post-events.

Wrappable attributes complete the following actions:

  • [Wrappable(false)] - Overrides the default capability for (non-final) public and protected methods to be wrapped, so it’s no longer possible to wrap the method. In other words, the method isn’t wrappable.
  • [Wrappable(true)] - Overrides the behavior of not being able to wrap methods that are marked as final, so it is possible to wrap the method. In other words, the method becomes wrappable.

Replaceable attributes complete the following actions:

  • [Replaceable (false)] - Overrides the behavior so that Chain of Command (CoC) must have an unconditional next call.
  • [Replaceable (true)] Overrides the behavior so that it’s possible to have a CoC extension, but they don’t need to unconditionally call next.

The replaceable method must also be wrappable.

The following code example shows that the method is protected to have pre-events and post-events and CoC by using [Hookable(false), Wrappable(false)], which means that no extensibility is available.

    /// <summary>
    /// Calculates and sets the <c>AmountCur</c> field using the <c>Quantity</c> and <c>UnitPrice</c>
    /// values.
    /// </summary>
    /// <param name="_qty">
    /// Item quantity on the line.
    /// </param>
    /// <returns>
    /// The <c>AmountCur</c> value.
    /// </returns>
    [Hookable(false), Wrappable(false)]
    public AmountCur calcLineAmount(Qty _qty = this.Quantity)
    {
        return this.salesPurchLineInterface().calcLineAmount(_qty);
    }

When you’re using attributes for methods, make sure that you’re aware of extensibility and potentially breaking it.