Event Handlers, Delegates & Attributes
Pre/post event handlers, table events, delegates, form events โ the complementary extensibility pattern to CoC.
Event Handlers, Delegates & Attributes
Events are door sensors โ they detect when something happens (record inserting, button clicked) and trigger your code. Unlike CoC which wraps the whole method, events hook into specific moments. Delegates let you create your OWN event points.
Pre and Post Handlers
public class SalesTableEventHandler
{
[PreHandlerFor(classStr(SalesTable), methodStr(SalesTable, validateWrite))]
public static void Pre_validateWrite(XppPrePostArgs _args)
{
SalesTable st = _args.getThis();
info(strFmt("Validating %1", st.SalesId));
}
[PostHandlerFor(classStr(SalesTable), methodStr(SalesTable, validateWrite))]
public static void Post_validateWrite(XppPrePostArgs _args)
{
boolean result = _args.getReturnValue();
if (!result) warning("Validation failed");
}
}
Event handlers are always static. XppPrePostArgs provides access to the object, parameters, and return value.
Table Data Events
[DataEventHandler(tableStr(CustTable), DataEventType::Inserting)]
public static void CustTable_onInserting(Common _sender, DataEventArgs _args)
{
CustTable ct = _sender as CustTable;
info(strFmt("Inserting: %1", ct.AccountNum));
}
[DataEventHandler(tableStr(CustTable), DataEventType::Inserted)]
public static void CustTable_onInserted(Common _sender, DataEventArgs _args)
{
CustTable ct = _sender as CustTable;
info(strFmt("Inserted: %1", ct.AccountNum));
}
| Event | When | Can Modify? |
|---|---|---|
| Inserting/Updating | Before DB write | Yes |
| Inserted/Updated | After DB write | No (need separate update) |
| Deleting | Before delete | Can cancel |
| ValidatingWrite | During validation | Add checks |
๐ Marcus: โI use post-insert handlers to trigger integration events. When a sales order inserts, my handler fires a business event to the warehouse.โ
Exam tip: Inserting vs Inserted timing
Inserting fires BEFORE the write โ field changes are included. Inserted fires AFTER โ the record exists but modifying it requires a separate update. The exam tests this timing distinction.
Delegates
public class OrderProcessor
{
delegate void onOrderProcessed(SalesId _id, boolean _success) { }
public void process(SalesId _id)
{
// ... logic ...
this.onOrderProcessed(_id, true); // fire event
}
}
// Subscribe from another class
public class NotificationHandler
{
[SubscribesTo(classStr(OrderProcessor), delegateStr(OrderProcessor, onOrderProcessed))]
public static void onProcessed(SalesId _id, boolean _success)
{
if (_success) info(strFmt("Order %1 done", _id));
}
}
Delegates define custom event points. Body is always empty. Subscribers use [SubscribesTo].
CoC vs Events
| Chain of Command | Event Handlers | |
|---|---|---|
| What | Wraps entire method | Hooks specific moment |
| Control flow | Can skip original (via no next) | Cannot prevent original |
| Access | this directly | Via event args |
| Best for | Modify logic, add validation | React, log, trigger integrations |
Marcus wants to notify an external system after customer creation without modifying data. Best approach?
Sophie needs to modify a field value before save. Which event?
Subscribe to a custom delegate?
Next up: Frameworks: SysOperation & Workflows