From my point of view, external event and idling are more or less the same thing. They are all called by Revit internal command loop.
A piece of fake code to show how things are working from my understanding. It definitely is more complicated.
public class RevitCommandLoop
{
private Queue<object> _commandQueue;
private UIApplication _app;
public RevitCommandLoop(UIApplication app)
{
_app = app;
_commandQueue = new Queue<object>();
}
public event EventHandler Idling;
public void Run()
{
while(true)
{
var command = _commandQueue.Dequeue();
if(command is IExternalEventHandler handler)
{
handler.Execute(_app);
}
if(command is IExternalCommand exCommand)
{
exCommand.Execute(...{parameters for IExternalCommand.Execute})
}
else
{
// no predefined commands to run, call idling event
OnIdling();
}
}
}
private void OnIdling()
{
this.Idling?.Invoke(this,EventArgs.Empty);
}
public void AddHandler(IExternalEventHandler handler)
{
_commandQueue.Enqueue(handler);
}
public void AddCommand(IExternalCommand command)
{
_commandQueue.Enqueue(command);
}
}