Transferring a Wall Type

Let's look at transferring a wall type from one document to another.

In fact, we already did so, way back in 2011, as an example about how to possibly approach the task of at least partially programmatically transferring project standards.

Now Parley submitted a comment on that, saying:

Question: We could still really use this... This post originally was from 2011. Any update on API access for this tool?

Answer: Glad to hear it sounds useful to you.

Well, nothing that I present here is really a tool, just sample source code for you to create your own tools from.

This should be pretty straightforward to migrate to Revit 2016, though.

On second thoughts, looking more closely at the text, I notice that I included the code above in The Building Coder samples as an external command CmdCopyWallType.

Therefore, it has been continually migrated every year, and the Revit 2015 version is provided in The Building Coder samples GitHub repository.

The code for the external command CmdCopyWallType is available there, already migrated to Revit 2015, and all the intervening versions as well.

As an added bonus, though, I went and tested the command for you.

I discovered that the transaction was not nicely encapsulated in a using statement, as it should be, so I fixed that.

I also discovered that a bug was introduced during the migration from Revit 2013 to 2014. Apparently, this command was never tested in Revit 2014 and the error remained undetected ever since. So I fixed that as well.

The Revit 2015 implementation now looks like this:

[Transaction( TransactionMode.Manual )]
class CmdCopyWallType : IExternalCommand
{
  /// <summary>
  /// Source project to copy system type from.
  /// </summary>
  const string _source_project_path
    = "Z:/a/case/sfdc/06676034/test/NewWallType.rvt";
 
  /// <summary>
  /// Source wall type name to copy.
  /// </summary>
  const string _wall_type_name = "NewWallType";
 
  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;
 
    // Open source project
 
    Document docHasFamily = app.OpenDocumentFile(
      _source_project_path );
 
    // Find system family to copy, e.g. using a named wall type
 
    WallType wallType = null;
 
    FilteredElementCollector wallTypes
      = new FilteredElementCollector( docHasFamily ) // 2014
        .OfClass( typeof( WallType ) );
 
    int i = 0;
 
    foreach( WallType wt in wallTypes )
    {
      string name = wt.Name;
 
      Debug.Print( "  {0} {1}", ++i, name );
 
      if( name.Equals( _wall_type_name ) )
      {
        wallType = wt;
        break;
      }
    }
 
    if( null == wallType )
    {
      message = string.Format(
        "Cannot find source wall type '{0}'"
        + " in source document '{1}'. ",
        _wall_type_name, _source_project_path );
 
      return Result.Failed;
    }
 
    // Create a new wall type in current document
 
    using( Transaction t = new Transaction( doc ) )
    {
      t.Start( "Transfer Wall Type" );
 
      WallType newWallType = null;
 
      wallTypes = new FilteredElementCollector( doc )
        .OfClass( typeof( WallType ) ); // 2014
 
      foreach( WallType wt in wallTypes )
      {
        if( wt.Kind == wallType.Kind )
        {
          newWallType = wt.Duplicate( _wall_type_name )
            as WallType;
 
          Debug.Print( string.Format(
            "New wall type '{0}' created.",
            _wall_type_name ) );
 
          break;
        }
      }
 
      // Assign parameter values from source wall type:
 
#if COPY_INDIVIDUAL_PARAMETER_VALUE
    // Example: individually copy the "Function" parameter value:
 
    BuiltInParameter bip = BuiltInParameter.FUNCTION_PARAM;
    string function = wallType.get_Parameter( bip ).AsString();
    Parameter p = newWallType.get_Parameter( bip );
    p.Set( function );
#endif // COPY_INDIVIDUAL_PARAMETER_VALUE
 
      Parameter p = null;
 
      foreach( Parameter p2 in newWallType.Parameters )
      {
        Definition d = p2.Definition;
 
        if( p2.IsReadOnly )
        {
          Debug.Print( string.Format(
            "Parameter '{0}' is read-only.", d.Name ) );
        }
        else
        {
          p = wallType.get_Parameter( d );
 
          if( null == p )
          {
            Debug.Print( string.Format(
              "Parameter '{0}' not found on source wall type.",
              d.Name ) );
          }
          else
          {
            if( p.StorageType == StorageType.ElementId )
            {
              // Here you have to find the corresponding
              // element in the target document.
 
              Debug.Print( string.Format(
                "Parameter '{0}' is an element id.",
                d.Name ) );
            }
            else
            {
              if( p.StorageType == StorageType.Double )
              {
                p2.Set( p.AsDouble() );
              }
              else if( p.StorageType == StorageType.String )
              {
                p2.Set( p.AsString() );
              }
              else if( p.StorageType == StorageType.Integer )
              {
                p2.Set( p.AsInteger() );
              }
              Debug.Print( string.Format(
                "Parameter '{0}' copied.", d.Name ) );
            }
          }
        }
 
        // Note:
        // If a shared parameter parameter is attached,
        // you need to create the shared parameter first,
        // then copy the parameter value.
      }
 
      // If the system family type has some other properties,
      // you need to copy them as well here. Reflection can
      // be used to determine the available properties.
 
      MemberInfo[] memberInfos = newWallType.GetType()
        .GetMembers( BindingFlags.GetProperty );
 
      foreach( MemberInfo m in memberInfos )
      {
        // Copy the writable property values here.
        // As there are no property writable for
        // Walltype, I ignore this process here.
      }
      t.Commit();
    }
    return Result.Succeeded;
  }
}

The updated version of The Building Code samples is release 2015.0.120.10.

So there you are.

Have fun!

Addendum: As Matt Taylor kindly points out below, the Revit 2014 API introduced the powerful copy and paste API, which can be used to easily implement a more complete solution that the one presented above.