Reloading a Family

Here is an impressively complete list of pretty fundamental beginner’s issues that you might potentially run into when reloading a family, starting from scratch, from a recent case handled by my colleague Joe Ye.
One of the interesting points that Joe ends up making is that in order to reload a family that has already been loaded into the document, you can use the LoadFamily overload taking an

IFamilyLoadOptions
argument.
Before and after getting to that stage, here are some other issues that you can potentially run into and need to resolve:

  1. Replacing the family type or symbol of a family instance with another type.
  2. Setting up an appropriate transaction.
  3. Reloading an already loaded family.
  4. Creating a new family type.

1. Changing the Symbol of a Family Instance

Question: How can I replace the family type or symbol of a family instance with some other type via the API?

Answer: The type of a family instance can be changed by modifying its Symbol property.
You can simply assign a new FamilySymbol instance to FamilyInstance.Symbol property.
Here is some pseudo code to illustrate this:


// the code to retrieve the new family symbol:
FamilySymbol newSymbol = ... ;
// the code to access the family instance:
FamilyInstance famInstance = ... ;
// change the family instance type:
famInstance.Symbol = symbol1;

By the way, the Revit SDK provides the Revit Developer Guide PDF file, which can guide you to the knowledge of programming on Revit and also provides some real sample code to achieve exactly what you need.

2. Setting up an Appropriate Transaction

Question: I followed your advice, but now I am facing an exception saying “A sub-transaction can only be active inside an open Transaction” in the following line:


// add a new type and edit its parameters
FamilyType newFamilyType
= familyManager.NewType("2X2");

I am trying to add a new type to the family in order to assign that as a replacement symbol to the family instance.
What could be going wrong here?

Answer: The reason might be that you have set up a manual transaction mode for your command.
You have to specify either manual or automatic transaction mode for you command.
You probably set up manual mode but omitted to explicitly start a transaction.
You can either change the mode to Automatic, or leave it as Manual and add the code to start and commit the transaction.

Here is an example of automatic transaction mode:


[TransactionAttribute( TransactionMode.Automatic )]
public class RevitCommand : IExternalCommand
{
  public Result Execute(
    ExternalCommandData commandData,
    ref string messages,
    ElementSet elements )
  {
    UIApplication app = commandData.Application;
    Document doc = app.ActiveUIDocument.Document;
 
    EditFamilyTypes( doc, famInstance );
 
    return Result.Succeeded;
  }
}

Here is an example of retaining the manual transaction model: start your own transaction first, and then commit it after executing the code to change the model:


[TransactionAttribute( TransactionMode.Manual )]
public class RevitCommand : IExternalCommand
{
  public Result Execute(
    ExternalCommandData commandData,
    ref string messages,
    ElementSet elements )
  {
 
    UIApplication app = commandData.Application;
    Document doc = app.ActiveUIDocument.Document;
 
    Transaction trans = new Transaction( doc, "ExComm" );
    trans.Start();
 
    EditFamilyTypes( doc, famInstance );
 
    trans.Commit();
    return Result.Succeeded;
  }
}

3. Reloading an Already Loaded Family

Question: The transaction handling improved matters.
Now the execution stops at the line


family = familyDoc.LoadFamily(doc);

It returns an error saying “Family loading failed”.

Answer: The error occurs because the family is already present in the current model.
If you use the Document.LoadFamily method overload taking a Document argument only to reload an existing family document, it will always fail.
Instead, you should use the LoadFamily overload that accepts an argument implementing the IFamilyLoadOptions interface.
Here is a simple implementation of such a class:


class FamilyOption : IFamilyLoadOptions
{
  public bool OnFamilyFound(
    bool familyInUse,
    ref bool overwriteParameterValues )
  {
    overwriteParameterValues = true;
    return true;
  }
 
  public bool OnSharedFamilyFound(
    Family sharedFamily,
    bool familyInUse,
    ref FamilySource source,
    ref bool overwriteParameterValues )
  {
    return true;
  }
}

With the IFamilyLoadOptions implementation in place, you can call the appropriate LoadFamily overload:


family = familyDoc.LoadFamily(
doc, new FamilyOption() );

<!–

Using this complicated sample to show the usage of changing a family type is not necessary, so I also wrote a simple command that changes a selected family instance symbol/type.
It retrieves all available family symbols that can be used for the picked family instance, and assigns one of them to the family instance:


[Transaction( TransactionMode.Manual )]
[Regeneration( RegenerationOption.Manual )]
public class Command1 : IExternalCommand
{
  public UIApplication app;
  public Document doc;
  public UIDocument uidoc;
 
  Result IExternalCommand.Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements )
  {
    app = commandData.Application;
    doc = app.ActiveUIDocument.Document;
    uidoc = new UIDocument( doc );
 
    Transaction trans = new Transaction( doc );
    trans.Start( "changeSymbol" );
 
    Selection sel = uidoc.Selection;
 
    Reference ref1 = sel.PickObject(
      ObjectType.Element,
      "Please pick a family instance" );
 
    FamilyInstance famInstance = ref1.Element as FamilyInstance;
 
    FamilySymbol famSymbol = famInstance.Symbol;
 
    ICollection<ElementId> symbols = famSymbol.GetSimilarTypes();
 
    FamilySymbol famSymbolOther = null;
 
    foreach( ElementId id in symbols )
    {
      if( false == id.Equals( famSymbol.Id ) )
      {
        famSymbolOther = doc.get_Element( id ) as FamilySymbol;
        break;
      }
    }
 
    if( famSymbolOther != null )
    {
      famInstance.Symbol = famSymbolOther;
    }
 
    trans.Commit();
 
    return Result.Succeeded;
  }
}

–>

4. Creating a New Family Type

Question: The updated code works fine when I only select one object.
If I select more than one object, it gives me error in the following line:


newFamilyType = familyManager.NewType("xx");

The error says “The type name xx is already in use”.
I need to able to select and modify the type of more than one object, and assign all of them the new type “xx”.
How can I achieve that, please?

Answer: If you are trying to change the type of more than one family instance, the new type does not need to be created repeatedly.
For the second family instance, you can bypass the code creating a new type using an ‘if’ conditional statement.

For completeness sake, here is
ReloadFamily.zip containing the complete Revit 2011 source code and Visual Studio solution of these various code snippets.

Many thanks to Joe for this exhaustive explanation!


Comments

16 responses to “Reloading a Family”

  1. Hi Jeremy,
    After i have create an extrusion in a family file, i try to load the family into a revit project. Everything works fine in Revit 2011, however, when i try to implement this in Revit 2012, it throw me an exception “Family Loading Failed”.
    Some code snippets
    Autodesk.Revit.DB.Document familyDocument = m_rvtApp.NewFamilyDocument(strTemplateFile);
    Autodesk.Revit.DB.Document projectDocument= commandData.Application.ActiveUIDocument.Document
    Transaction trans = new Transaction(familyDocument , “Create Family”);
    try
    {
    if (trans .Start() == TransactionStatus.Started)
    {
    ………….(Add reference plane)
    ………….(Add alignment)
    ………….(Add dimension)
    familyDocument .LoadFamily(projectDocument, new FamilyOption());
    trans.Commit();
    return Result.Succeeded;
    }
    catch (Exception ex)
    {
    trans.RollBack();
    return Result.Failed;
    }
    Any idea why this works in Revit 2011 but failed in Revit 2012?
    Thanks you for your time.

  2. Dear Bsyap,
    No, I have never previously heard of the “Family Loading Failed” error that you describe.
    Have you resolved the issue by now? If so, what was causing it, please?
    Cheers, Jeremy.

  3. Hello, Jeremy.
    I have a problem again:(
    I’m trying to load family to the document. The code is very simple:
    var doc = commandData.Application.ActiveUIDocument.Document;
    IFamilyLoadOptions familyLoadOptions = new FamilyLoadOptions();
    Family family;
    var res = doc.LoadFamily(fileName, familyLoadOptions, out family);
    where filename is correct filename of family.
    This code works well when I load families from Autodesk Library. But when I load my own family Revit show me to strange dialogs. The first one: “Invalid column unit type:”, and the second one: “Could not parse column header: ?????????”
    res variable of course false.
    But then I load this family through the user interface, there are no errors and family loaded correctly.
    I thoght, may this behavior becase family file contains cyrrilyc symbols and saved this family as 1.rfa. Then I loaded 1.rfa family I got other error dialog: “Row 1: Unacceptable list separator: \ Acceptable list separators are: , ; : |”
    What is it? Is it a bug?
    If you want I can send you my family.
    P.S. We submitted ADN Application yesterday. Hope soon we will be an ADN member:)

  4. One interesting thing.
    If I select FamilyInstance in 3D-Model, in user interface click “Edit Family” button then save this family then I try to load saved family to entire document I get two error dialogs described in previos post and Docuemnt.LoadFamily returns false. If I try to load this family via user interface I get error dialogs either but the family loaded into document.
    But the most interesting things, if I select FamilyInstance and save family via API
    famDoc = family.Document.EditFamily(family);
    SaveAsOptions sao = new SaveAsOptions();
    sao.OverwriteExistingFile = true;
    res = famDoc.SaveAs(path, sao);
    And later load saved family into document throgh user interface or API – there no errors.
    Jeremy, can you explain this strange behavior?
    I have at least one family that have this behavior. I want to try why it happens, because I need it in my next project.
    Regards, Victor

  5. Woong Ki Sung Avatar
    Woong Ki Sung

    Hi Jeremy,
    Your blog is always so helpful.
    Now I am testing a editing FamilyTypes code, and I have a transaction problem even though I set proper manual transactions. (I am using revit 2013) The code is very simple, so could you please check? In advance, thank for your help.
    file :: http://dl.dropbox.com/u/39185526/familyEdit.cs

  6. Dear Woong Ki Sung,
    Thank you for your appreciation.
    Funnily enough, I already received the answer to your question from Matt mason a week before, suggesting that I point explicitly point out this change, so I have now done so:
    http://thebuildingcoder.typepad.com/blog/2012/05/edit-family-requires-no-transaction.html
    Cheers, Jeremy.

  7. This line of code: Dim newFamilyType As FamilyType = familyManager.NewType(“xx”)
    Creates a new family type that’s a copy of an existing family type. Is there any way to control what existing family type it copies? For example, I have a family of air handlers, with 6 different types, AH-1 through AH-6. When I execute the command it copies AH-6 and creates the new type xx, which is a copy of AH-6, just named xx. Instead I’d like to copy AH-3 and make that the new type xx. Is this possible?

  8. Dear Matt,
    I think you can use the FamilyManager.CurrentType property to set the current type.
    If you set it to AH-3 before calling NewType, it might do what you wish.
    Good luck.
    Cheers, Jeremy.

  9. Worked perfect. Thank you.

  10. Jeremy,
    I believe a slight change to your IFamilyLoadOptions example is necessary in order for it to be compatible with 2013: the “ref”s need to be replaced by “out”.
    My apologies if this has been pointed out elsewhere, but if it was, I didn’t see it.
    Regards,
    Joel
    (Ref: http://forums.autodesk.com/t5/Autodesk-Revit-API/IFamilyLoadOptions-implementation-in-revit-2013/m-p/3585706#M2951)

  11. Dear Joel,
    Thank you very much for pointing it out!
    You are absolutely right, of course, and the link to the discussion forum is perfect.
    As you can see above, this was published over a year back for Revit 2012, and I obviously cannot go back and update all the old articles every time a new version is released. I wish it was possible :-)
    Cheers, Jeremy.

  12. Hello Jeremy,
    I just downloaded the code, and run it without any change. but it always throw me an exception “Family Loading Failed”. Do you know why? Thanks

  13. Sorry, I downloaded the code for BeamMaker.
    Below is the Link:
    http://thebuildingcoder.typepad.com/blog/2010/07/beam-maker-using-a-void-extrusion-to-cut.html

  14. Dear sir
    I am new to revit app development env..I need help in one concept..
    I am using concept of transaction and subtransaction while drawing coupling on duct.
    Previously I was trying to open transaction each time while drawing coupling on duct.
    Now when i tried to open transaction once and then open subtransaction each time while drawing coupling on duct then facing problem as below
    FamilyInstance famInst = _rvtDoc.Create.NewFamilyInstance(Pos, famSymbol, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
    when i hover on “famInst” and look at POINT location then we can it is been set as
    {(0.000000000, 0.000000000, 0.000000000)}
    This is happening only when i am applying subtransaction.

  15. Hi Jeremy,
    I’ve been reading this article in detail and mixed it with some coding on my own, and came to the following conclusions:
    – When trying to add a new Type in a Family that does not have any Type created:
    1) If the Family contains some geometry I get the following error: “Attempted to read or write protected memory. This is often an indication that other memory is corrupt.”
    2) If the Family does not contain geometry (like Tags) then the new Type is created correctly.
    I read above in a comment that there must be at least one Type already defined for the FamilyManager.NewType(“xx”) method to work. Is there any way I can create a new Type to a Family with no Types previously created?
    Thanks in advance.

  16. Dear Ema,
    Please work through the Family API labs.
    They show how to create a family from scratch, add types and other important family definition features, and do not generate such an error.
    They are described here:
    http://thebuildingcoder.typepad.com/blog/2009/08/the-revit-family-api.html
    An up-to-date version including the full training material scripts is provided here:
    http://thebuildingcoder.typepad.com/blog/2012/09/exporting-parameter-data-to-excel.html
    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