Image courtesy of Hobart, Yañez, Ramos, Maguey, and Martínez Applied Dynamics: Using Dynamic Model Update in the Autodesk® Revit® API Scott Conover Software Development Manager, Revit API Objectives Register dynamic updaters Add triggers to invoke the updaters when a target element has changed Implement a dynamic updater to react to model changes Store/update application specific data from updaters Use the document changed event to keep external application data synchronized Agenda 5 minutes 20 minutes 5 minutes Dynamic changes Dynamic Model Update DocumentChanged event 10 minutes Failure processing 10 minutes Idling event Static vs. Dynamic changes in the Revit API A static change refers to an action that A dynamic change refers to changing changes the model as an effect of an one-time explicit request made by the end user. Revit is in between commands, sort of idling, ready to accept a new transaction. a) b) c) By executing an external command By clicking on a ribbon widget By executing a macro the model as an reaction to something happening in or with the model. Revit is already about to make a change, is in the midst of a change, or has just completed a change. a) b) An event handler A dynamic update callback Actions The end user is the direct trigger for a static change. taken by the user ultimately cause the dynamic change, but the application has control over what actions it should react to 4 Frameworks for dynamic change Four Revit API frameworks support dynamic code affecting what happens at the model level: Dynamic model update Something is being changed DocumentChanged event Something has been changed FailuresProcessing event Application Idling event Something has triggered a warning or error Nothing is being currently changed All of these events have special relationships with the Transaction and Failure reporting frameworks. Frameworks for dynamic change Application.Idling Transaction.Start() Dynamic Update – loop Starts Updater1.Execute() Updater2.Execute() Dynamic Update – loop Ends Failure processing Application.DocumentChanged Application.Idling committing Transaction.Commit() Transaction model changes Dynamic model update Adding logic to regeneration Dynamic Model Update Updates the document while the user is making changes React to changes that already happened Make changes to Revit elements Keep external data stored in the model in sync Part of the transaction process Runs when a transaction is committed Not executed when a transaction is undone or redone Invoked for desired changes only, controlled by filters It’s best for performance if updater is only called when actually needed Simple updater Changing wall type 9 IUpdater interface The interface All methods except Execute() invoked only once at the time of registration, to get information about the updater: Id Name Additional info (used in user messages) ChangePriority Execute() is invoked every time a particular updater is triggered Revit holds a reference of the updater instance (so it is not garbage collected accidentally) public interface class IUpdater { UpdaterId GetUpdaterId(); void Execute(UpdaterData data); ChangePriority GetChangePriority(); String GetUpdaterName(); String GetAdditionalInformation(); }; 10 Registering updaters Best times to register: During the OnStartup method of an IExternalApplication (applicationwide) During the DocumentOpened callback (document-specific) During the Module_Startup of a VSTA macro Otherwise users may be prompted about a missing updater for a document Updater Id Consists of the AddInId plus an updater-specific GUID Why it’s required: Revit needs to know what application an updater belongs to Only the owning application can register and unregister an updater Updater information is cached in the Revit documents which are modified by the updater Only manifest files support AddInIds (not Revit.ini), so only manifest-registered applications can register updaters. Application vs. Document registration Application-wide updaters invoked on changes in any document cannot be used with explicit trigger scopes (element ids) can trigger on elements which pass a given ElementFilter Use for general purpose applications Document-level updaters invoked only for changes in the target document can trigger on specific element ids can also trigger on elements which pass a given ElementFilter Use for special logic for a certain project, or for documents where a specific tool was run to create or modify a special set of elements 13 Change Priority Determines the order of execution of registered updaters Setting a wrong priority could slow down Revit Highest priority: GridsLevelsReferencePlanes Lowest priority: Annotations Making a change of higher priority (when executing an updater) is possible Because higher priority items were changed, additional updaters (including your own) will have to be called again to potentially react to changes Could result in a circular dependency Priority is requested only once during updater registration Update Triggers Required for Revit to know what changes an updater is interested in When a trigger is engaged, the corresponding Updater is called by invoking its Execute() method Scope An Change type Trigger updater without triggers will never be executed Triggers for an updater cannot be modified while inside the Execute() method Trigger - Scope Part of the document to trigger on Can be Application-wide or Document-wide Can be explicit (set of element IDs) or implicit (filters) Explicit scope only Document-wide Ids are not checked against the document Ids are not synchronized after reload latest Trigger - ChangeType Specifies the kind of change in which the updater is interested Addition and Deletion Parameter – changes of values of element parameters Set using a specific Parameter from an element Trigger fires for any document (for BuiltInParameters) Trigger fires for source document only (for shared parameters) Geometry – shape and location in space Any encapsulates every change Except for addition and deletion Execution of an updater Evaluated at the end of every transaction Execute() method called for each updater whose trigger matches Execute() may be invoked more than once in a single transaction Updaters not invoked for undo and redo Revit will restore all document changes Added vs. Deleted vs. Changed elements Net change is reported Due to actions of other updaters There is a limit in place to prevent an infinite loop Added, then changed – added is reported Added, then deleted – not reported Finding what trigger was hit IsChangeTriggered() Use if there is more than one trigger on a particular updater Forbidden operations during Dynamic Update Calling certain methods If they start a transaction If they must be called outside of a transaction UI methods If they affect a bi-directional interdependency between elements (this restriction is due to possible inconsistency of worksets) Rare; APIs which cause them are listed as forbidden in the documentation Modifying the current transaction Modifying the current transaction group Changing updater registration and triggers Competing updaters Updaters prohibited from explicitly changing the same data Can be indirectly changed (due to regeneration) Data is the “same” if: Belongs to the same element Represents the same portion of the same element Examples: Two updaters change different parameters of wall – OK Two updaters change height parameter – forbidden Two updaters change the curve driver of a wall - forbidden Even if one moves it in X, one moves it in Y Missing updaters Revit Remembers updaters Checks for remembered updaters on document open This is for protection of data integrity of the document 21 Misbehaving updaters Unhandled exceptions Loop caused by interaction of two updaters The first one that makes a change again in the last allowed cycle Number of allowed cycles = number of updaters + 2 If a faulty updater is removed, the cycle is repeated one more time. If there is a change from another updater, that one will be removed as well, and so on 22 Updater examples Building relationships between elements 23 Updater examples Custom family behavior 24 Document Changed Event What just happened? The DocumentChanged event Raised at the end of any transaction Raised when rolling back a group All transactions enclosed by the group will be included Raised for every undo and redo Even if rolled back or empty Multiple transactions at once Not raised if non-persistent data changes (for example: ) Loading/creating a new shared parameter file Accessing analysis visualization framework entities View operations The DocumentChanged event At this time, the transaction framework is not expecting further changes (so the event is read-only with respect to the document) Purpose of this event is to keep non-document data in synch with Revit External databases External UI Analysis visualization The DocumentChanged event List of Added / Deleted / Modified element ids is available Any of the lists can be empty Net change is reported Added, then changed – added is reported Added, then deleted – not reported Cumulative within all transactions being processed When multiple transactions undone or redone, all net changes are reported 28 Failure Processing Posting and reacting to problems Defining and posting failures Failure definition defined in OnStartup() Post failure message during open transaction Assigned severity (warning, error, corruption) Assigned problematic elements for highlighting Assign resolutions API-supported resolutions: Rollback of transaction (“cancel”) Deletion of failing elements “Delete other elements” resolution Reacting to failures Three options FailuresPreprocessor Specific transaction Suppress warnings or handle errors possibly raised by your transaction FailureProcessing Global event See and react to warnings and errors before user does FailureProcessor Final handler for failures Normally, Revit’s UI acts as the FailuresProcessor for the session Implementing this interface will allow your application to handle all errors instead (UI will not be used) Idling Event Let me make changes gradually… Idling event Raised continually whenever the interactive user is not doing something else Not raised when user in a Revit tool Not raised when there is any open transaction Not raised in modes where API commands are not supported Perspective views Schedule views In-place family editing Not raised when there is no active document Idling event The Idling event callback allows you do almost anything: Start a transaction Make model changes Regenerate Commit transactions Read Revit data When coding, remember that this event happens in between user actions Callback actions should be small and contained Large modifications or calculations will be perceived by user as making Revit unresponsive Idling event The Idling event provides the framework to support asynchronous calculations Multithreaded processing Calculations in the cloud Response to modeless dialog boxes All Revit interaction needs to happen during the Idling event callback Extract and cache data needed for the calculation before returning control to Revit Idling event driven external calculation with AVF 35 Q&A Special thanks to: Arnost Lobel, Revit API Software Developer, who developed much of this course initially Harry Mattison, Revit API Software Developer, whose code was the basis for the Idling and Failure Handling samples Autodesk [and other] are registered trademarks or trademarks of Autodesk, Inc., and/or its subsidiaries and/or affiliates in the USA and/or other countries. All other brand names, product names, or trademarks belong to their respective holders. Autodesk reserves the right to alter product and services offerings, and specifications and pricing at any time without notice, and is not responsible for typographical or graphical errors that may appear in this document. © 2010 Autodesk, Inc. All rights reserved.