I just picked up an ADN case on a topic that was already raised yesterday in the Revit API discussion forum thread on Revit 2018 API undocumented changes, so it is definitely worth highlighting here as well:
- Question
- Change in behaviour
- Exceptions should be exceptional
- Answer
- The Building Coder samples
CmdPlaceFamilyInstance
Question
A bug may have been introduced into the Revit 2018 API UIDocument
PromptForFamilyInstancePlacement
method.
In Revit 2017, hitting the Escape
key twice after placing the families would end the command.
In Revit 2018, hitting the Escape
key twice generates an OperationCanceledException
and all the elements that were just placed are deleted.
The problem can be observed by comparing the behaviour of the Revit 2017 SDK PlacementOptions
sample add-in with the Revit 2018 SDK version of the PlacementOptions
sample add-in.
Change in Behaviour
Matt Taylor describes the situation differently in his Revit API discussion forum thread on Revit 2018 API undocumented changes:
Each year I upgrade my codebase for use with the new version of Revit. Each year, I rid my code of deprecated and/or obsolete function warnings/errors.
Each year I seem to find an undocumented change in the way the Revit API works.
'The Factory', can we please have a more detailed and complete list of changes? Can you add this change to the documentation, please?
My 'find' this year is a change in the way PromptForFamilyInstancePlacement
works.
This function used to just return focus to your function upon cancelling by the Reviteer.
In Revit 2018, cancelling of this function by your Reviteers throws an Exceptions.OperationCanceledException
[sic] exception.
Easily fixed, once discovered:
Try docUi.PromptForFamilyInstancePlacement(FamilySymbol) Catch ex As Exceptions.OperationCanceledException ' The user cancelled placement. ' This should only trigger in Revit 2018. ' Do something if you like End Try
This change even makes sense!
It's a good idea!
It also fills me with dread. What else is going to throw an exception unexpectedly?
What other changes are there?
(Yes, I know that this item is vaguely alluded to in the 'what's new' document, but it's not documented anywhere.)
Have you found any hidden 'treasures' that you want to share?
Exceptions Should be Exceptional
Greg 'Sherbs' adds a very valid additional point:
Yikes!
Good catch!
This is more than a bit concerning.
Undocumented exceptions are generally going to be application fatal.
I hope this sort of thing can be addressed more systematically in upcoming releases.
Regarding the specific find, my opinion differs:
There really is nothing 'exceptional' or 'unexpected' here.
Cancelling placement may be infrequent, but it is an entirely normal user action.
Why even throw in this case at all?
I'm not terribly passionate about this, just throwing out another viewpoint.
I'm a bit of minimalist when it comes to the use of exceptions.
By Stephen Charles Thompson – Own work, CC BY-SA 3.0, Link
Answer
Many thanks to Matt for pointing this out!
I would say that this change in behaviour is precisely alluded to, not vaguely, in the documentation of What's New in the Revit 2018 API section on UIDocument.PromptForFamilyInstancePlacement() behavioral change:
The behavior for UIDocument.PromptForFamilyInstancePlacement() was changed to be same as that of PickObject() methods...
Raising the exception you mention corresponds exactly to the PickPoint
behaviour.
However, just as you say, the detailed consequences are not explicitly spelled out.
I also fully agree with Greg's statement: exceptions should be exceptional.
Expected behaviour should not be communicated using exceptions.
I have been preaching this for years to little avail:
- Fixing RvtMgdDbg for MEP Connectors
- Duplicate Mark Values
- Selecting Model Elements
- Language Independent Subcategory Creation
- Exporting Parameter Data to Excel, and Re-importing
- Parameter DisplayUnitType, Bretagne and Decompilers
- External Command Lister and Adding Ribbon Commands
- The Pick Point Methods Throw an Exception on Cancel
- Never Catch All Exceptions
To answer the original question raised above: You need to catch and handle (or ignore) the OperationCanceledException
as shown by Matt.
If you code does not, your transaction will presumably not be committed.
The family instances that were successfully placed before the user cancelled the placement and the exception was thrown are probably removed as the transaction is rolled back.
No bug, just a change in behaviour.
I hope this clarifies and all is now illuminated.
The Building Coder Samples CmdPlaceFamilyInstance
I implemented
the external command CmdPlaceFamilyInstance
in The Building Coder samples to
exercise the PromptForFamilyInstancePlacement
method when it was originally introduced.
It also includes code using the DocumentChanged
event
to retrieve the newly created elements.
I updated it to handle the OperationCanceledException
as shown by Matt
in release 2018.0.132.2.
Here is the diff to the preceding release that shows exactly what modifications were made.
Here is the diff to the preceding release that
shows exactly what modifications were made; simply add an exception handler around the call to PromptForFamilyInstancePlacement
:
try { uidoc.PromptForFamilyInstancePlacement( symbol ); } catch( Autodesk.Revit.Exceptions.OperationCanceledException ex ) { Debug.Print( ex.Message ); }