Before reading the rest of the article:
- If you want a basic understaning of the external events, check the previous article https://digitteck.com/dotnet/revitapidotnet/revit-external-event/
- DOWNLOAD the Visual studio solution I used VisualStudio2019 Community edition for this example.
- Also, take a look at the project properties under Debug and BuildEvents and change the settings appropriately. If you used the default locations for installing Revit then all you have to do is change the revit version to your version (2018 to whatever you have)
Transaction Handling in Revit is not a complex job, it’s only a bit tedious to think an easy to work with system. For me I hate it to define an event for each transaction I want to make, and there is no reason to do so when I can define a generic way and just pass an action that I want to create.
And because there is no good or bad answer, no easy or hard procedure, I will not simplify this and instead I will present the method I used for my latest addin, a pool of transaction workers.
In fact, in this solution I have to ways of executing a transaction in Revit.
- The files inside the TransactionUnits folder are actually not part of the transaction worker pool, instead this was an experiment that uses a transaction which when raised creates a new transaction with my custom action inside (because transactions must be registered in Revit context not in our app context)
- The files inside TransactionHandling folder (outside TransactionUnits folder) create the transaction worker pool.
The manager class initializes the ExternalEventWorkerPool which contains all our workers (here we have defined 4 workers) and the queue of TransactionUnits.
The transaction unit contains the actions to be performed within a transaction.
The ExecuteInternal method is called in the following scenarios:
- when a queue item has finished processing
- when a queue item is added in the queue
The Execute internal will try to get a worker, it a worker is not available then it will not execute. No worries, this means that when a worker finishes the job,
the execute internal will be called again and the work will eventually be performed
The worker pool contains a list of workers and whenever one worker is needed, it’s moved from the available list to the inUse list.
Note : Release unit is actually passed to the worker. When the transaction is finished, an event is raised and that event will trigger this method. The Release unit method will also trigger the WorkerRelease method which will determine the transaction manager to execute the ExecuteInternal method that checks for other items in the queue
This is the external event that Revit will execute. There is one ExternalEventHandler assigned for each worker and you can see that we also have a TransactionDetails class here.
This transaction-details is setup by the worker from the TransactionManager.ExecuteInternal -> ExternalEventWorker.Setup method chain.