Event Handlers (Pre & Post Events) in Dynamics 365 Finance & Operations
Question 2 — Delegate-based extensibility, syntax, and when to use them instead of Chain of Command.
Interview Question
Model Answer (Short)
Event handlers are static methods that subscribe to delegates raised by a method.
A Pre event (OnMethodCalled style, using DataEventHandler) fires
before the target method executes, while a Post event fires after it completes.
You attach them using attributes like [PreHandlerFor(...)] / [PostHandlerFor(...)], and
access parameters and return values through the XppPrePostArgs object. They are loosely coupled and
upgrade-safe, but unlike Chain of Command you cannot control the flow (the base method always runs).
Detailed Explanation
Pre event handler
Runs before the target method. Useful for validating or modifying input parameters before the
standard logic executes. You read/write parameters through XppPrePostArgs.getArg() and
setArg().
Post event handler
Runs after the target method. Ideal for reacting to the result — for example, reading or
overriding the return value via args.getReturnValue() and args.setReturnValue().
Prerequisites (Rule 5)
- Visual Studio with the Dynamics 365 developer tools installed.
- A custom model / package referencing the package that owns the target object.
- The subscribed handler must be a public static method inside a class.
- Understanding of the
XppPrePostArgsandFormControlEventArgshelper classes.
Code Example — Pre event handler
Validating a parameter before a table method executes:
class SalesTableEventHandlerAbc
{
[PreHandlerFor(tableStr(SalesTable), tableMethodStr(SalesTable, checkUpdate))]
public static void checkUpdate_Pre(XppPrePostArgs args)
{
// Read the calling object
SalesTable salesTable = args.getThis();
// Read an incoming argument (0-based index)
boolean forceUpdate = args.getArg('_forceUpdate');
if (salesTable.CustAccount == '')
{
throw error("Customer account cannot be blank.");
}
}
}
Post event handler — overriding the return value
class SalesTablePostHandlerAbc
{
[PostHandlerFor(tableStr(SalesTable), tableMethodStr(SalesTable, mustBeApproved))]
public static void mustBeApproved_Post(XppPrePostArgs args)
{
boolean ret = args.getReturnValue();
// Force approval requirement regardless of base logic
ret = true;
args.setReturnValue(ret);
}
}
Form control event handler
[FormControlEventHandler(formControlStr(SalesTable, ApproveBtn), FormControlEventType::Clicked)]
public static void ApproveBtn_OnClicked(FormControl sender, FormControlEventArgs e)
{
SalesTable salesTable = sender.formRun()
.dataSource(tableStr(SalesTable))
.cursor();
salesTable.Status = SalesStatus::Approved;
salesTable.update();
}
Event Handler vs. Chain of Command
| Aspect | Event Handler (Pre/Post) | Chain of Command |
|---|---|---|
| Coupling | Loosely coupled (delegate subscription) | Tightly coupled (method wrapping) |
| Control over base logic | None — base method always runs | Full — you decide whether to call next |
| Parameter access | Via XppPrePostArgs (weakly typed) |
Directly, strongly typed |
| Handler type | Must be public static |
Instance method in a final class |
| Best used when | Many hooks on form elements; reacting to events | Default choice; need to alter the method flow |
Points the interviewer wants to hear
- Event handlers subscribe to delegates and are public static.
- Pre runs before, Post runs after — the base method always executes.
- Use
XppPrePostArgsto read/modify parameters and the return value. - Prefer event handlers when a form has many hooks to avoid too many CoC methods.
- They are upgrade-safe because the base object is never modified.
Likely Follow-up Questions
- Can a Post event handler change the return value? (Yes, via
setReturnValue().) - What is the difference between a
DataEventHandlerand a delegate? - Why is CoC generally recommended over event handlers for method-level logic?
Key Takeaway
Event handlers give you loosely coupled, upgrade-safe hooks before and after a method — but cannot stop the base logic. Reach for them on form controls and event-driven scenarios, and choose Chain of Command when you need to control or replace the method flow.