Creating a new Family Symbol

This post is due to Joe Ye in our Beijing office. Many thanks, Joe! While proof reading my handouts for the Revit API tips and tricks session at AU, DE205-3 Enhancing Your Revit Add-In, Joe pointed out that creating a new type or family symbol is a hot topic often asked by developers. It is not obvious from the Revit API help documentation or samples how to achieve this. It is simple to solve, though: one can use the Duplicate() method to create a new type, and then modify the parameters or properties required.

Here is an example in VB duplicating a wall type by doubling the thickness of each layer in its compound layer structure:

Public Function Execute( _
  ByVal commandData As ExternalCommandData, _
  ByRef message As String, _
  ByVal elements As ElementSet) _
As IExternalCommand.Result _
Implements IExternalCommand.Execute
    Dim app As Application = commandData.Application
    Dim doc As Document = app.ActiveDocument
    Dim els As ElementSet = doc.Selection.Elements
    Dim e As Element
    Dim newWallTypeName As String _
      = "NewWallType_with_Width_doubled"
    For Each e In els
      If TypeOf e Is Wall Then
        Dim wall As Wall = e
        Dim wallType As WallType
        wallType = wall.WallType
        Dim newWallType As WallType
        newWallType = wallType.Duplicate(newWallTypeName)

        Dim layers As CompoundStructureLayerArray
        layers = newWallType.CompoundStructure.Layers
        Dim layer As CompoundStructureLayer
        For Each layer In layers
          layer.Thickness *= 2
        wall.WallType = newWallType
        Exit For
      End If
    Return IExternalCommand.Result.Succeeded

  Catch ex As Exception
    message = ex.ToString()
    Return IExternalCommand.Result.Failed
  End Try

End Function

This command iterates over the currently selected elements. If a wall has been selected, its wall type is retrieved and duplicated to create a new wall type. In its compound layer structure, the thickness of every layer is doubled, and the new wall type is assigned to the selected wall. The command terminates as soon as the first selected wall has been processed.

Here is a different example in C# duplicating a column type, setting a new fixed value for its radius:

public CmdResult Execute(
  ExternalCommandData commandData,
  ref string message,
  ElementSet elements )
  Application app = commandData.Application;
  Document doc = app.ActiveDocument;
  string familyName = "Concrete-Round-Column";
  Filter f = app.Create.Filter.NewFamilyFilter(
    familyName );
  List<RvtElement> families = new List<RvtElement>();
  doc.get_Elements( f, families );
  if( 1 > families.Count )
    message = "No suitable family found.";
    return CmdResult.Failed;
  Family fam = families[0] as Family;
  FamilySymbol famSym = null;
  foreach( FamilySymbol fs in fam.Symbols )
    famSym = fs;
  // create a new family symbol using Duplicate:
  string newFamilyName = "NewRoundColumn 3";
  FamilySymbol newFamSym = famSym.Duplicate(
    newFamilyName ) as FamilySymbol;
  // set the radius to a new value:
  Parameter par = newFamSym.get_Parameter( "b" );
  par.Set( 3 );
  return CmdResult.Succeeded;