List Linked Files and TransmissionData

Today is the day of our

Revit 2012 API webcast
, in just six hours’ time!
In case you missed it so far, I assume that there is still time for a

last minute registration
.

I mentioned that one of the new features in the Revit 2012 API is the

access to linked file information
and
the TransmissionData class which stores information about all of the external file references in a document.
The TransmissionData for a Revit project can be read without fully opening the document in the user interface.

Now the following simple question on this cropped up which prompted me to explore this in a little further depth:

Question: Is it possible to list all linked files with their paths Revit API?

Answer: Yes, it definitely is, and the Revit 2012 API makes it very easy to do so.

The overview of the

access to linked file information
lists
the TransmissionData class mentioned above.
Its description in the Revit API help file RevitAPI.chm states:

A class representing information on all external file references in a document.

TransmissionData stores information on both the previous state and requested state of an external file reference. This means that it stores the load state and path of the reference from the most recent time this TransmissionData’s document was opened. It also stores load state and path information for what Revit should do the next time the document is opened.

As such, TransmissionData can be used to perform operations on external file references without having to open the entire associated Revit document. The methods ReadTransmissionData and WriteTransmissionData can be used to obtain information about external references, or to change that information. For example, calling WriteTransmissionData with a TransmissionData object which has had all references set to LinkedFileStatus.Unloaded would cause no references to be loaded upon next opening the document.

This enables the implementation of code to list all the links of a given Revit document.
Here is a method ListLinks which exercises the new TransmissionData class to achieve exactly that:


/// <summary>
/// List all DWG, RVT and other links of a given document.
/// </summary>
void ListLinks( ModelPath location )
{
  string path = ModelPathUtils
    .ConvertModelPathToUserVisiblePath( location );
 
  string content = string.Format(
    "The document at '{0}' ",
    path );
 
  List<string> links = null;
 
  // access transmission data in the given Revit file
 
  TransmissionData transData = TransmissionData
    .ReadTransmissionData( location );
 
  if( transData == null )
  {
    content += "does not have any transmission data";
  }
  else
  {
    // collect all (immediate) external references in the model
 
    ICollection<ElementId> externalReferences
      = transData.GetAllExternalFileReferenceIds();
 
    int n = externalReferences.Count;
 
    content += string.Format(
      "has {0} external reference{1}{2}",
      n, PluralSuffix( n ), DotOrColon( n ) );
 
    links = new List<string>( n );
 
    // find every reference that is a link
 
    foreach( ElementId refId in externalReferences )
    {
      ExternalFileReference extRef
        = transData.GetLastSavedReferenceData( refId );
 
      links.Add( string.Format( "{0} {1}",
        extRef.ExternalFileReferenceType,
        ModelPathUtils.ConvertModelPathToUserVisiblePath(
          extRef.GetPath() ) ) );
    }
  }
  Debug.Print( content );
 
  TaskDialog dlg = new TaskDialog( "List Links" );
 
  dlg.MainInstruction = content;
 
  if( null != links && 0 < links.Count )
  {
    string s = string.Join( "  rn",
      links.ToArray() );
 
    Debug.Print( s );
 
    dlg.MainContent = s;
  }
  dlg.Show();
}

It takes a ModelPath argument to determine the document to analyse.
The ModelPath can be instantiated from a normal file pathname using the ModelPathUtils class methods, for instance like this using the current active document in the Execute method of an external command:


public Result Execute(
  ExternalCommandData commandData,
  ref string message,
  ElementSet elements )
{
  View view = commandData.View;
 
  if( null == view )
  {
    message = "Please run this command in an active document.";
    return Result.Failed;
  }
  else
  {
    Document doc = view.Document;
 
    ModelPath modelPath = ModelPathUtils
      .ConvertUserVisiblePathToModelPath(
        doc.PathName );
 
    ListLinks( modelPath );
 
    return Result.Succeeded;
  }
}

Here is the output it generates in a simple sample model:

List links output

The output is also listed as text in the Visual Studio debug output window:


The document at 'C:tmplinked_file2.rvt' has 3 external references:
KeynoteTable RevitKeynotes_Metric.txt
RevitLink walls.rvt
CADLink TestHouse.dwg

Here is
ListLinks.zip
containing the entire Visual Studio solution implementing this command.

There is obviously still room for improvement to this.
Currently it is hardwired to analyse the active document.
It would probably be useful to be able to select one or more other documents.

Here are some simple ideas for a useful end user utility to list all links in user selected Revit files which could be easily implemented:

  • Select one or more Revit documents.
  • Run ListLinks on them.
  • Display the results in a modeless dialogue and terminate the command.
  • Add a ‘save to text file’ button to the form.

Please let me know if you are interested in an improved version implementing some of these, and we’ll see whether I ever get around to doing it.


Comments

19 responses to “List Linked Files and TransmissionData”

  1. Hi Jeremy, Unfortunately I missed the webcast (time zone). Will it be available as a download? Incidently I backpacked through Dogubayazit past Mt Ararat in the mid 70s. Fascinating area.

  2. Dear Dale,
    Sorry to hear that you missed the webcast, but not to worry. It was recorded and will be published quite soon. The recording will be made available from the ADN training schedule site, and I’ll point to it from the blog as well.
    Wow, you were in Dogubayazit in the 70s? Yes, very fascinating indeed! That was our base base (base-squared?) camp, where we stayed in a hotel the nights before and after spending four days and three nights in tents on the mountain. Our guides were kurds, and they gave us an impression of kurdish culture, songs and cuisine.
    Cheers, Jeremy.

  3. Jeremy,
    2 questions on this; First, I see that you can list out the keynote file, is there any way to reload the file into Revit? Any way to change it?
    Second, Can you tell me how to find the location or tranform of a linked file in a document? I am trying to determine if family instances in a linked document are in a room in the current document. I can get into the linked file and find the location of instances in that file, and I can find out if a point is in a room in main file, but I need to figure out how to transform the coordinates based on the location of the linked file in the main file…
    Thanks for any help you can give,
    Steve

  4. Dear Steve,
    I am not aware of any possibility to reload the keynote file programmatically.
    Regarding the location of linked files, that should all be completely solved in the Revit 2012 API. Have a look at the What’s New section in the SDK documentation.
    Cheers, Jeremy.

  5. Mike Caruso Avatar
    Mike Caruso

    Hi Jeremy,
    Reviving an old thread, I know, but could you tell me what method is used to set a new path on an RVT link? Let’s say the original link was moved to another drive…
    Thank you,
    Mike

  6. Dear Mike,
    Reviving an old thread is perfectly fine!
    Teaching an old dog new tricks? Yes, we can!
    And actually, it is not that old at all.
    I guess TransmissionData is the right place to look, at least. How about:
    GetLastSavedReferenceData: Gets the ExternalFileReference representing path and load status information concerning the most recent time this TransmissionData’s document was opened.
    GetDesiredReferenceData: Gets the ExternalFileReference representing path and load status information to be used the next time this TransmissionData’s document is loaded.
    Or maybe what you are looking for is WriteTransmissionData? That seems to allow you to specify a new path…
    The RevitAPI.chm entry on the TransmissionData class includes a sample.
    Please let us know how it works out for you, I’d love to write about that.
    Cheers, Jeremy.

  7. Mike Caruso Avatar
    Mike Caruso

    Hi Jeremy,
    WriteTransmissionData looks like what I need but throws an exception (Unable to write transmission data). My code is very similar to the API help, just in my case I am changing the paths, not unloading the links.
    Have you taken a stab at using that method?
    Regards,
    Mike

  8. Dear Mike,
    I have not myself, but my colleagues have and encountered no problems.
    Are you following the restriction that the file being modified must be closed?
    Here is some code that works fine:
    [Transaction(TransactionMode.Manual)]
    public class Foo : IExternalCommand
    {
    static AddInId m_appId = new AddInId(new Guid(“CF184371-E65A-4a35-BA4F-2959CA87A42D”));
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
    UIApplication uiapp = commandData.Application;
    UIDocument uidoc = uiapp.ActiveUIDocument;
    Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;
    Document doc = uidoc.Document;
    FilePath location = new FilePath(“C:\file.rvt”);
    TransmissionData transData = TransmissionData.ReadTransmissionData(location);
    if (transData != null)
    {
    // collect all (immediate) external references in the model
    ICollection externalReferences = transData.GetAllExternalFileReferenceIds();
    // find every reference that is a link
    foreach (ElementId refId in externalReferences)
    {
    ExternalFileReference extRef = transData.GetLastSavedReferenceData(refId);
    if (extRef.ExternalFileReferenceType == ExternalFileReferenceType.RevitLink)
    {
    // we do not want to change neither the path nor the path-type
    // we only want the links to be unloaded (shouldLoad = false)
    transData.SetDesiredReferenceData(refId, new FilePath(“C:\MyNewPath\cut.rvt”), extRef.PathType, true);
    }
    }
    // make sure the IsTransmitted property is set
    transData.IsTransmitted = true;
    // modified transmission data must be saved back to the model
    TransmissionData.WriteTransmissionData(location, transData);
    }
    else
    {
    Autodesk.Revit.UI.TaskDialog.Show(“Unload Links”, “The document does not have any transmission data”);
    }
    return Result.Succeeded;
    }
    }
    Can you confirm that this works for you as well? Thank you!
    Cheers, Jeremy.

  9. Dear Mike,
    I wanted to do this anyway, and now a comment from Guming prompted me to finally go ahead and promote the answer to your comment to above to a blog post of its own:
    http://thebuildingcoder.typepad.com/blog/2011/10/using-the-writetransmissiondata-method.html
    Thank you!
    Cheers, Jeremy.

  10. Jeremy, sorry for posting on an older post, but I’m using this example to find the KeynoteTable path. I’ve noticed, however, that if a user changes the Keynote Settings in a project the KeynoteTable is not updated to the correct path. Is there someway to have the KeynoteTable update after a users has changed the Keynote Settings?

  11. Dear Anthony,
    Not to worry, feel free to comment anywhere you please.
    I am glad that you can make use of this sample.
    Nope, I was not aware that it is not updated, and I do not know how that could be forced.
    If you are an ADN member, please submit a DevHelp Online case for use to explore this further.
    Cheers, Jeremy.

  12. Thanks for your response.  The TransmissionData must be written when the file closes, which makes sense.  Since I wanted the option for the user to update the paths I used ExternalFileUtils.GetAllExternalFileReferences to read the KyenoteTable path.
    Im not a developer at all, just a guy trying to develop a few addins for me and my companys use so I only use the ADN Open forums and reference your blog for sample code.  I completed my first addin utilizing a bunch of samples you had to update a series of keynote tags in a drafting for all the materials keynotes in the project.  Its not glamorous, but it allows us to have a keynote generated in a view, which populates a Master Keynote Legend with the materials keynotes.
    Thanks for the great resources and response!!!

  13. Hi Jeremy,
    I got a question about phase map between host doc and linked doc.
    I know Revit provides a UI to manage the mapping, which is triggered by selecting the linked model and clicking Edit Type in Property Panel. However I didn’t find anything relative in API doc or your blogs.
    Did I miss something? Thanks a lot!
    Best Regards,
    David Tan

  14. Dear David,
    Nope, sorry, I am not aware of any such mapping in the API.
    We do have an open wish list item SPR #203054 [Access to data in RVT_LINK_PHASE_MAP] related to this.
    I added a note of your wish to this item in order to make the development team aware of its importance.
    Cheers, Jeremy.

  15. Hi Jeremy,
    Thanks for your clarification and efforts on the wish list!
    At this moment, I can unify the phase name to make program knows the consistency between host RVT phases and linked RVT phases.
    On the other hand, I got a mess about host and links recently, while the phase mapping issue is one of them. We have a big RVT model which contains a couple of linked RVTs. The customer expects that the program could handle the selection event of the element in linked RVT. 
    I found a solution of selection event on your blog, which is sweet. But it doesn't work for element in the linked RVT. You know, via Revit UI, we can move the mouse over the element in the linked RVT and press TAB to make it highlighted. Although the Property Panel won't show the properties of this highlighted element in the linked RVT, but it looks like to be selected.
    I know how to retrieve the element in linked RVT from DB document (from your blog again). But how to make it selected in UI document? It seems Revit doesn't support this feature. Do you have any suggestion on this? Thanks a lot!
    Best Regards,
    David Tan
    To: flower4wine@outlook.com

  16. CR Zhao Avatar
    CR Zhao

    Hello,Jeremy
    I wonder how to creat “Groups-Model”using revit api.
    And how to load group using revit api.
    Thank you ..
    Best Regards,
    Chengrui Zhao
    To: soft_rainy@163.com

  17. Dear Chengrui Zhao,
    Use the ItemFactoryBase.NewGroup method to create a group.
    There is no way to load one directly.
    In Revit 2014 you can use the new copy and paste API to bring one in from another document, though.
    Cheers, Jeremy.

  18. dolives@techniptps.com Avatar
    dolives@techniptps.com

    Hi Jeremy,
    With SharpDevelop now is it possible to do the same thing:
    List Linked Files and TransmissionData
    And how ?
    Daniel OLIVES (A french user)
    dolives@techniptps.com

  19. Dear Daniel,
    I would assume that you create a SharpDevelop macro and plug in the code above into it.
    Good luck!
    Cheer, Jeremy.

Leave a Reply to Steve FaustCancel reply

Discover more from Autodesk Developer Blog

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

Continue reading