Place Family Instance

The Revit SDK does not include any example of calling the new PromptForFamilyInstancePlacement method, which prompts the user to interactively and graphically place instances of a specified family symbol, so I am creating a new Building Coder sample command to demonstrate its use.

At the same time, I can answer an interesting follow-on question:

Question: I am starting to use PromptForFamilyInstancePlacement to get the user to place one or more instances of a family symbol.
This method returns void.
It would be nice if it returned the instances that were placed instead.

Anyway, how can I find the new instances after this call?
Does the Revit API provide anything like the (entlast) idea in good old AutoLISP?

For example, I would like to call the PromptForFamilyInstancePlacement method and then assign some parameter values to the new family instances immediately afterwards.

Answer: I already discussed


retrieval of newly added elements
to
the database.
It presents one approach making use of the element ids, which grow monotonously as new elements are added.
However, the

comment by Guy Robinson

to that suggestion points out a much more reliable and officially supported method to obtain the newly added elements using the

DocumentChanged event

and the newly added element id collection provided to its event handler.
Before we get to that, though, let’s look at the call to PromptForFamilyInstancePlacement itself.

PromptForFamilyInstancePlacement

The Revit API help file
RevitAPI.chm makes the following remark about this method:

This method opens its own transaction, so it’s not permitted to be invoked in an active transaction. In a single invocation, the user can place multiple instances of the input family type until they finish the placement (with Cancel or ESC or a click elsewhere in the UI). The user will not be permitted to change the type to be placed. Users are not permitted to change the active view during this placement operation (the operation will be completed).

In case you wonder, if you do try to run it in a command with automatic transaction mode, i.e. with a transaction opened automatically by Revit for the external command, the following exception is thrown:

  • Autodesk.Revit.Exceptions.InvalidOperationException: “It’s not permitted to run this API method in an active transaction.”

In other words, if you wish to make use of this method, you are forced to use the new and improved manual transaction mode.

The method takes a family symbol argument to define the component being placed in the model, and there is no other input required or possible.

Retrieving Newly Created Elements

As suggested above, to retrieve the newly created elements added to the model by the call to PromptForFamilyInstancePlacement, one can simply subscribe to the DocumentChanged event.
The event handler is called with a DocumentChangedEventArgs instance which includes a method GetAddedElementIds to return all newly added element ids.

One thing to be aware of is that this method is called each time a placement is made, i.e. repeated calls are made for repeated placements within one single call to PromptForFamilyInstancePlacement.
In the sample presented below, each call will report one single element added.
If you want to collect all the element ids added, you need to append them to some global collection.

As always, every single event handler or other reactor added to a system will cause additional overhead, so it makes sense to minimise the use of event handlers.
In this case, this can be easily achieved by adding the handler immediately before prompting for the instance placement, and removing it immediately afterwards.

CmdPlaceFamilyInstance

I implemented a new Building Coder sample command CmdPlaceFamilyInstance to demonstrate the issues outlined above:

  • Use manual transaction mode.
  • Define a variable _added_element_ids to collect the newly added element ids in the DocumentChanged call-back method.
  • Use a filtered element collector to retrieve a symbol defining the type of family instances to be placed, in this case doors.
  • Subscribe to the DocumentChanged event immediately before prompting for placement.
  • Call PromptForFamilyInstancePlacement to interactively place one or more instances.
  • Unsubscribe from the DocumentChanged event.
  • Report the number of instances placed in the model.

The OnDocumentChanged event handler at the end is trivial, because it just adds all newly created element ids to our local global collection:


[Transaction( TransactionMode.Manual )]
[Regeneration( RegenerationOption.Manual )]
class CmdPlaceFamilyInstance : IExternalCommand
{
  List<ElementId> _added_element_ids = new List<ElementId>();
 
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements )
  {
    UIApplication uiapp = commandData.Application;
    UIDocument uidoc = uiapp.ActiveUIDocument;
    Application app = uiapp.Application;
    Document doc = uidoc.Document;
 
    FilteredElementCollector collector
      = new FilteredElementCollector( doc );
 
    collector.OfCategory( BuiltInCategory.OST_Doors );
    collector.OfClass( typeof( FamilySymbol ) );
 
    FamilySymbol symbol = collector.FirstElement() as FamilySymbol;
 
    _added_element_ids.Clear();
 
    app.DocumentChanged
      += new EventHandler<DocumentChangedEventArgs>(
        OnDocumentChanged );
 
    uidoc.PromptForFamilyInstancePlacement( symbol );
 
    app.DocumentChanged
      -= new EventHandler<DocumentChangedEventArgs>(
        OnDocumentChanged );
 
    int n = _added_element_ids.Count;
 
    TaskDialog.Show(
      "Place Family Instance",
      string.Format(
        "{0} element{1} added.", n,
        ( ( 1 == n ) ? "" : "s" ) ) );
 
    return Result.Succeeded;
  }
 
  void OnDocumentChanged( object sender, DocumentChangedEventArgs e )
  {
    _added_element_ids.AddRange( e.GetAddedElementIds() );
  }
}

Note that it is always important to unsubscribe from events as soon as possible to minimise the overhead that all your callbacks will cause.

Here is

version 2011.0.74.0
of The Building Coder samples including the complete source code and Visual Studio solution and the new command.


Comments

35 responses to “Place Family Instance”

  1. Dan Tartaglia Avatar
    Dan Tartaglia

    Hi Jeremy,
    Is it possible to envoke the Escape key, Modify command or end the transaction so that PromptForFamilyInstancePlacement() can be used to place a different symbol without user input? For example, I’d like to specify a listbox containing al family types for a specific catagory of families, allow a user to select a type/symbol and place the family. The user could then select another type to place without ending the command.
    Thanks,
    Dan

  2. Dear Dan,
    Nothing in the current Revit API that I am aware of enables you to switch the symbol being used by PromptForFamilyInstancePlacement. Hhowever, you can still take a look at
    http://thebuildingcoder.typepad.com/blog/2010/11/launching-a-revit-command.html
    It describes a workaround for a similar specific case, namely simulating some user keystrokes and using the ‘Create Similar’ command in a clever combination to set up the wall command so that a specific wall type is pre-selected. I don’t seeing it being much help for your specific case, but it shows you the limitations and possibilities and may hopefully help trigger some brilliant idea for you.
    Cheers, Jeremy.

  3. Dear sir,
    How can i give user prompt to draw PVC pipe by PromptFamilyInstance() .
    Thanks & Regards,
    -Nitin

  4. Dear Nitin,
    I assume you mean PromptForFamilyInstancePlacement, not PromptFamilyInstance.
    I do not believe that a PVC is in fact a family instance.
    Therefore, I do not believe that you can use PromptForFamilyInstancePlacement to manipulate it, can you?
    Cheers, Jeremy.

  5. No, i cannot. Thanks for quick reply.

  6. Shawn Schrader Avatar
    Shawn Schrader

    Jeremy,
    When using PromptForFamilyInstancePlacement(), is there a way to change the default from “Place on Vertical Face” to “Place on Face”? Also, is there a way to turn the default “Tag on Placement” off?
    Thanks,
    Shawn

  7. Dear Shawn,
    As far as I know, there is no possibility at all to influence the behaviour of PromptForFamilyInstancePlacement.
    Is there a way to turn off the default “Tag on Placement” in the standard user interface?
    If so, it should work for PromptForFamilyInstancePlacement as well.
    Cheers, Jeremy.

  8. sangsen Avatar
    sangsen

    Hi Jeremy,
    Is there any way to use ISelectionFilter or to filter out some elts in promptforfamilyInstancePlacement() method.
    Thanks in advance,

  9. Dear Sangsen,
    No, because PromptForFamilyInstancePlacement places one single pre-defined symbol passed in as an argument and does not do any picking.
    Cheers, Jeremy.

  10. Hi Jeremy,
    Do you have a vb.net version of this example?
    I can normally translate macros, but I’m having trouble with the RaiseEvents part.
    Thanks & regards,

  11. Dear Matt,
    Nope, sorry, I don’t, I never touch the stuff :-)
    You can recreate this entire application from scratch in VB in about 86 seconds, though, so there should not really be any need to use a translator…
    To prove the point, I used the Visual Studio Revit add-in wizard and created the following code:
    Here it is, except I don’t know how to do typeof in VB:
    Dim _added_element_ids As List(Of ElementId) _
    = New List(Of ElementId)
    Public Function Execute(
    ByVal commandData As ExternalCommandData,
    ByRef message As String,
    ByVal elements As ElementSet) _
    As Result Implements IExternalCommand.Execute
    Dim uiapp As UIApplication = commandData.Application
    Dim uidoc As UIDocument = uiapp.ActiveUIDocument
    Dim app As Application = uiapp.Application
    Dim doc As Document = uidoc.Document
    Dim collector As FilteredElementCollector _
    = New FilteredElementCollector(doc)
    collector.OfCategory(BuiltInCategory.OST_Doors)
    ‘collector.OfClass( typeof(Autodesk.Revit.DB.FamilySymbol) )
    Dim symbol As FamilySymbol _
    = collector.FirstElement()
    _added_element_ids.Clear()
    AddHandler app.DocumentChanged,
    AddressOf OnDocumentChanged
    uidoc.PromptForFamilyInstancePlacement(symbol)
    RemoveHandler app.DocumentChanged,
    AddressOf OnDocumentChanged
    Dim n As Integer = _added_element_ids.Count
    Return Result.Succeeded
    End Function
    Public Sub OnDocumentChanged( _
    ByVal sender As Object, _
    ByVal e As DocumentChangedEventArgs)
    _added_element_ids.AddRange(e.GetAddedElementIds())
    End Sub
    Cheers, Jeremy.

  12. Hi Jeremy,
    Oh dear, I think I was overthinking it…
    I appreciate your help.
    FYI, the usage of oftype in VB.NET:
    collector.OfType(Of DB.FamilySymbol)()
    Take care & stay well.
    Regards,
    Matt

  13. Dear Matt,
    Thinking is error prone and should be avoided whenever possible :-)
    Thank you for the VB snippet :-)
    No, actually, trying to use your suggestion, I discover it does not work at all and is completely different from what I meant.
    I do not mean OfType, I mean to call the filtered element collector method OfClass. In C#, it takes a argument typeof(Autodesk.Revit.DB.FamilySymbol). I still don’t know how to formulate that in VB. Well, actually, searching the samples, I found the solution, which is
    collector.OfClass(GetType(FamilySymbol))
    Cheers, Jeremy.

  14. Jeremy,
    I agree. But if you have to think, coffee helps!
    Haha, I use ofclass (as you show it) a lot. I tested the oftype in connection with other filter refinements, so I guess I just got lucky when it worked!
    Thanks for your help – have a good week! :)
    Matt

  15. ahmed ali Avatar
    ahmed ali

    thank you put this method only place element in vertical face
    and im asked that if thier is any way to place the face based objects.
    for example place face based lighting family on ceilling
    regards
    ahmed ali

  16. Jeremy, How would I adapt this code to place a detail component in a drafting view?

  17. Dear Enoch,
    I don’t see any need to change anything at all. Do you?
    Cheers, Jeremy.

  18. How do I pass my symbol name in as an argument for this to place my symbol from a command button?

  19. Dear Enoch,
    You can encapsulate the code above into a method ‘f’ taking the symbol and family names or better still the symbol element id as an argument.
    Implement an external application setting up the command button and an external command to handle the button click.
    On the button click launching the command, determine the symbol element id and pass it in to your method ‘f’.
    To see how to implement an external application and an external command and filter for elements to determine the symbol element id, work through the Revit API getting started material:
    http://thebuildingcoder.typepad.com/blog/2012/07/obj-model-exporter-with-transparency-support.html#4
    Cheers, Jeremy.

  20. Skootamota Avatar
    Skootamota

    Hello Jeremy,
    How would you go about inserting a family instance on a work-plane. Using
    PromptForFamilyInstancePlacement
    it defaults to face based placement. How could you insert a family instance with Placement – Place on work-plane?

  21. Dear Skootamota,
    Thank you, good question.
    Yes, indeed, how would you?
    No idea.
    Can you tell me?
    Thank you!
    Cheers, Jeremy.

  22. Skootamota Avatar
    Skootamota

    Hello Jeremy,
    Do you know if there is a fix from the API development team in the works for this? Everything I’m coding needs this work plane placement to work somehow, but I can’t seem to come up with a fix.

  23. Dear Skootamota,
    Nope, and I am not aware of any such problem either.
    Is there one at all?
    Try looking at this:
    http://thebuildingcoder.typepad.com/blog/2011/11/pick-a-point-in-3d.html
    Please let us know if you still have trouble.
    Thank you!
    Cheers, Jeremy.

  24. Skootamota Avatar
    Skootamota

    Hello Jeremy,
    I’m not sure how this would help? With the PromptForFamilyInstancePlacement command, you can see the instance before placement, align the instance up against a 2D line, like a wall line in a DWG (that’s on the workplane) before finally selecting the placement location. Like placing a receptacle annotation (with 3d family model) for instance. I have found how to select a workplane, but there doesn’t seem to be any method to place an instance on the workplane. If you know of a way to get this to work, I’d really appreciate even the smallest of code snippets.

  25. Dear Skootamota,
    Yup, I hear what you say.
    Afaik, PromptForFamilyInstancePlacement is the only way to achieve that.
    Are you sure you are going with the flow, and not fighting it?
    Maybe your family definition is simply inappropriate? What template is it based on? What is the purpose?
    Cheers, Jeremy.

  26. Skootamota Avatar
    Skootamota

    Everytime I reply it doesn’t seem to show up.

  27. Skootamota Avatar
    Skootamota

    Hello Jeremy,
    There are many instances where it is desirable to place instances on a work-plane. For one, Electrical Fixtures that are suspended from a ceiling. For a second, with linked DWG files on levels (work-planes) used to create a wire frame model, you could do the entire design in Revit.
    I’m at an impasse to our company adopting Revit and programming up automation features until this work-plane placement works somehow. Any chance you could convince the API developers to add this feature? I’ll join ADN Professional if that would help speed up the process somehow.

  28. Skootamota Avatar
    Skootamota

    Hello Jeremy,
    The option to choose between a work-plane and face is presented on the Ribbon for instance placement. It’s surprising that this super important option isn’t available from the API.

  29. Dear Skootamota,
    Thank you for pointing out that Revit itself does support this functionality.
    I’ll check for you.
    Cheers, Jeremy.

  30. Dear Skootamota,
    Sorry to say, I confirmed that this functionality is not currently available.
    We have registered wish list item #188792 for it.
    Cheers, Jeremy.

  31. skootamota Avatar
    skootamota

    Thanks, that’s good to hear. I hope they will push this one through quickly, as it deals with essential fundamental use of Revit.

  32. Skootamota Avatar
    Skootamota

    Hello Jeremy,
    Is there any chance the API ‘wish list’ item #188792 is in the works? Is there a way users can check the status of a wish list item? If it’s not being worked on is there anything I can do to speed up development?

  33. Harry Mattison Avatar
    Harry Mattison

    Hi Jeremy,
    Is there any update for 2015 or beyond about placing a family instance via the API on a work plane?
    Thanks
    Harry

  34. Dear Harry,
    Not that I am aware of.
    Are you after something specific?
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading