Transfer Project Standards

Developers occasionally ask about programmatic access to the ‘Transfer Project Standards’ user interface functionality.
Unfortunately, that is currently not provided by the Revit API.
However, it is possible to implement a workaround, although it would require quite a bit of work and testing to ensure that it fulfils your needs, as the following sample by Joe Ye shows:

Question: Is it possible through the 2012 Revit API to transfer project standards and or system families between Revit projects?

For example, through the Revit user interface, I can insert drafting views from another project.
I can also transfer wall types, fill patterns, line styles, text types, and various other project wide settings from one project to another.
Alternatively, if I only want to transfer the types related to one object, I can copy and paste a complex object like a railing from one project into another.
This will not only copy the railing type but also the related types such as rail profiles and baluster families.

Is there a way to automate this through the Revit 2012 API?

Answer: I am sorry to say that there is currently no API access to the built-in ‘Transfer Project Standards’ functionality.

A possible workaround would obviously be to read the system types of interest from the source project, determine similar existing elements in the target project, use

the Duplicate method

to create new target instances of them, and copy all relevant properties from the source to the new target elements.

I implemented a new external command CmdCopyWallType for The Building Coder solution from Joe’s sample code that shows the principles of implementing this for a wall type.

The source wall type is selected from an existing project by name, an equivalent new target wall type is created in the current project, and the properties are copied across.

Some aspects are not handled here, e.g. element-id-valued and shared parameters, other properties, the compound structure, etc.

It does give you the general idea, however, proves feasibility in principle, and provides a starting point if you really want to take this further.

Here is the CmdCopyWallType implementation:


[Transaction( TransactionMode.Manual )]
class CmdCopyWallType : IExternalCommand
{
  /// <summary>
  /// Source project to copy system type from.
  /// </summary>
  const string _source_project_path
    = "C:/a/j/adn/case/bsd/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;
 
    foreach( WallType wt in docHasFamily.WallTypes )
    {
      if( wt.Name.Equals( _wall_type_name ) )
      {
        wallType = wt;
        break;
      }
    }
 
    if( null == wallType )
    {
      message = string.Format(
        "Cannot find source wall type '{0}'"
        + " in source document '{1}'. ",
        _source_project_path,
        _wall_type_name );
 
      return Result.Failed;
    }
 
    // Create a new wall type in current document
 
    Transaction t = new Transaction( doc );
 
    t.Start( "Transfer Wall Type" );
 
    WallType newWallType = null;
 
    foreach( WallType wt in doc.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;
  }
}

It prints out some of its actions in the debug output window.

As you can see from the following list, some properties cannot be copied without adding more intelligence, so there is not even a guarantee that the resulting wall style will work as expected:


New wall type 'NewWallType' created.
Parameter 'Description' copied.
Parameter 'URL' copied.
Parameter 'Type Comments' copied.
Parameter 'Fire Rating' copied.
Parameter 'Cost' copied.
Parameter 'Assembly Code' copied.
Parameter 'Structure' not found on source wall type.
Parameter 'Coarse Scale Fill Pattern' is an element id.
Parameter 'Wrapping at Inserts' copied.
Parameter 'Function' copied.
Parameter 'Model' copied.
Parameter 'Manufacturer' copied.
Parameter 'Type Mark' copied.
Parameter 'Coarse Scale Fill Color' copied.
Parameter 'Assembly Description' is read-only.
Parameter 'Keynote' copied.
Parameter 'Width' is read-only.
Parameter 'Wrapping at Ends' copied.

As said, this is just an idea and a starting point for further exploration.
It is a long way removed from providing the full functionality to transfer project standards.

Here is
version 2012.0.92.0 of
The Building Coder samples including both the command

CmdFilledRegionCoords
that
I presented last week and the new command CmdCopyWallType.


Comments

9 responses to “Transfer Project Standards”

  1. Hi Jeremy:
    I have a question need you help.How can I use Revit API to set workplane?For example,I create a sketch plane and I want to set this sketch plane to workplane.Can you give me some help?
    Thanks very much!
    Guming.

  2. Dear Guming,
    Use the View.SketchPlane property introduced in the Revit 2011 API.
    For an example, please refer to the PlaceAtPickedFaceWorkplane command presented by the Selections SDK sample.
    Cheers, Jeremy.

  3. Dear Jeremy:
    Thanks for reply,I will try it.
    Thank you very much!
    Guming.

  4. Dear Jeremy,
    can you please show a sample how I can transfer complete walls with structures and layers between 2 projects with API?
    Thank you very much!
    Peter

  5. Dear Peter,
    Sorry, I do not have anything at hand right now, nor any time to explore.
    If you do, please share it with us and I will create a new post on this.
    The above should provide a usable starting point, and the good news is that the Revit 2012 API does provide all the tools you need to create the required compound layer structure.
    Thank you!
    Cheers, Jeremy.

  6. Dhananjay Avatar
    Dhananjay

    Hi Jeremy,
    With Revit 2014 and 2015, is there an API which will help in doing Transfer Project Standards?
    Thanks
    regards,
    Dhananjay

  7. Parley Avatar
    Parley

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

  8. Dear Parley,
    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:
    https://github.com/jeremytammik/the_building_coder_samples
    The code shown above is thus available there, already migrated to Revit 2015, and all the intervening versions as well:
    https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/CmdCopyWallType.cs
    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 has been undetected since. So I fixed that as well.
    The updated version is release 2015.0.120.10:
    https://github.com/jeremytammik/the_building_coder_samples/releases/tag/2015.0.120.10
    So there you are.
    Cheers, Jeremy.

  9. Dear Parley,
    Since I like your question and my answer so much, I promoted the whole thread to a new dedicated blog post:
    http://thebuildingcoder.typepad.com/blog/2015/05/transferring-a-wall-type.html
    Cheers, Jeremy.

Leave a Reply to gumingCancel reply

Discover more from Autodesk Developer Blog

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

Continue reading