Updater Queues Multi-Transaction Operation for Idling

I recently pointed out that certain operations require multiple transactions to complete.

The dynamic model updater framework DMU, on the other hand, takes complete control over the transaction handling, making it impossible to incorporate such a multi-transaction operation.

The updater framework is designed to enable an add-in to incorporate its own additional behaviour into a running transaction to react to changes in the model. The advantage is that the entire operation including the custom add-in behaviour is encapsulated in one single transaction. This comes at a price, as said: the add-in has no control whatsoever over the transaction management. It thus also obviously cannot add additional transactions into the process.

Let me present a powerful and generic workaround to this limitation, suggested by Rudolf Honke.

He ran into this issue when trying to group elements in an updater, for instance for his dynamic insulation and dynamic arrangement of elements on a terrain surface tools. The dynamic insulation group behaves almost like a custom entity in AutoCAD:

The element arrangement on terrain can be used to place trees, lampposts, and other objects to follow a curve and update automatically to changes in the curve:

The narration for these two videos is in German, by Mr Honke himself. The dynamic insulation tool is also available in an English version, but that has not yet been uploaded.

Both of these tools generate and handle groups of elements and react dynamically to later changes of the model.

The reaction makes use of the DMU; there is no other choice. However, the entire update operation requires ungrouping, modifying and regrouping of elements and cannot be achieved within the single transaction provided.

Additional transactions in the IUpdater would be required to handle this gracefully.

In lack of this, here is Rudolf's workaround:

  1. In the updater, save a list of elements requiring update.
  2. Subscribe to the Idling event.
  3. In the Idling event handler, call the standard add-in command that has no restrictions on its transaction handling.
  4. In the command, process the queued up elements and clear the list.
  5. Unsubscribe from Idling.

In the actual implementation, the elements obviously maintain some data about their relationships, so the modification of an element can easily discover which other elements are affected.

Here are a few more details and several reasons why this is necessary:

The IUpdater context is fine for just setting parameters, but these tools need more than that, e.g. deleting elements, creating new ones, adding extensible storage data to handle the element connection logic, handling Failures, etc.

I recently ran into a different case where a developer was trying to make use of the InstanceVoidCutUtils class to insert a void on a modified wall within the updater Execute method. This caused Revit to display an error message saying "Third party updater Xyz has experienced a problem and its action had to be canceled." Removing the one single line triggering the void generation from the updater enables to operation to complete, but the void is still missing, of course. That seems to me like a prime use case for Rudolf's approach as well.