Context of Events in Microsoft Dynamics NAV

Microsoft Dynamics NAV 2016 introduced events, and a big change it was too. If we want to execute some code when something happens in the standard application we can do so without changing any standard code – as long as the ‘something’ has an event associated with it.

One of the most useful examples of this is table events. When a record is inserted, modified, renamed or deleted we want to know about it and have the option to execute some code when it happens.

2 important points to consider:

  1. Your event subscription will be triggered when temporary records are inserted/modified/renamed/deleted. You may not be interested in these events so you should EXIT when this is the case. See Record.ISTEMPORARY.
  2. Your event subscription will be triggered with and without the trigger code having been executed i.e. INSERT(TRUE) and INSERT(FALSE) will both trigger your event subscription. The RunTrigger parameter of your subscription will tell you which it was.

All clear so far? Good, let’s continue.

I’ve got a scenario where I want to know when Sales Line records have been inserted or deleted by the user. When the user inserts/deletes a record on a page INSERT(TRUE)/DELETE(TRUE) will always be called. This means my event subscriptions can test whether RunTrigger is true, and if not, exit without doing anything. This is necessary because there are some places where Sales Lines will be inserted/deleted that I don’t want to know about e.g. lines being DELETE(FALSE)ed when a sales order is posted.

But wait, there are some cases of INSERT(FALSE) that I do want to know about. For instance the Copy Document Mgt. codeunit. That inserts sales lines with INSERT(FALSE) so will be ignored by my code but it’s a scenario I want to react to.


Q: How can I tell why my event subscription is being triggered?

A: Put a breakpoint on your code, debug a session that calls your code and look at the call stack window.


Q: Yes, but how do I get at that information from my code?

A: It’s ugly, but there is a way.


The GETLASTERRORCALLSTACK function returns some text that has the details of all the object types, ids, functions and code line numbers that were being executed at the time of the last error.

If I throw an error in my code I can then use GETLASTERRORCALLSTACK to analyse the code that was being executed at that point in time and therefore know how my event subscription ended up being called.

Obviously, I can’t just do something like:

ERROR(‘’);
CallStack := GETLASTERRORCALLSTACK;

as the code will be stopped by the error. Instead I can use a TryFunction to throw the error in a way that won’t prevent the rest of the code from executing.

IF NOT ThrowError THEN
  CallStack := GETLASTERRORCALLSTACK;

//analyse the call stack and decide what to do…

LOCAL [TryFunction] ThrowError()
ERROR(‘’);

I told you it was ugly 😉 but it might be a solution worth considering. A few other points to consider:

  • Handle try functions with care. Vjeko discusses the subject at some length here: http://vjeko.com/whats-new-in-nav-2016-splitting-atoms-with-tryfunction
  • None of this would be necessary if you were prepared to make modifications to some standard objects. If that is an option in your scenario then weigh the benefits of having a small/no footprint in standard NAV vs. the complexity/performance hit of this option.
  • Be mindful of how often your code might get executed.
    • Only resort to reading the call stack when absolutely necessary and then spend time making your code as efficient as possible.
    • It would be a shame to have beautiful context-aware event subscriptions that couldn’t be used because they made the system too slow.

Leave a Reply