Getting linked file data w/out opening the RVT

Here’s how to get information about linked files (DWG, RVT, etc) without having to first open the file

public void GetRVTLinks()
{
    ModelPath mp = new FilePath(@"C:\Users\harry_000\Documents\testFile.rvt");
    TransmissionData td = TransmissionData.ReadTransmissionData(mp);
    string s = "ExternalFileReferenceType\tPathType\tFile Path" + Environment.NewLine;
    foreach (ElementId id in td.GetAllExternalFileReferenceIds())
    {
        ExternalFileReference extRef = td.GetLastSavedReferenceData(id);
        s += extRef.ExternalFileReferenceType.ToString() + "\t" +
             extRef.PathType.ToString() + "\t" + 
            ModelPathUtils.ConvertModelPathToUserVisiblePath(extRef.GetPath()) + Environment.NewLine;
    }
    
    string outputfile = Path.Combine(Path.GetTempPath(),"links.txt");
    using (StreamWriter sw = new StreamWriter(outputfile,false))
    {
        sw.Write(s);
    }
    
    Process.Start(outputfile);
}

Deleting (almost) all Viewport Types in 2014

A friend who is still running Revit 2014 on their Windows NT box noticed that yesterday’s post works only in 2015 because it uses the newfangled ElementType.FamilyName Property.

So that you can continue living happily in the Stone Age, here is a different way to find the Viewport Types based on the presence of the Viewport Type-specific parameters.

Also, while testing this Revit kept giving me a¬†nonsensical¬†“Deleting all open views in a project is not allowed” error, even though I was never trying to delete all open views in the project. It seems that Revit 2014 & 2015 really really really love Viewport 1 and don’t want it to be deleted. So I added some code to leave it alone.

public void deleteUnusedViewportTypesFor2014()
{
    Document doc = this.ActiveUIDocument.Document;
    
    // get all viewport types
    // this approach to find the Viewport Types can be used in 2014 
    // whereas the ElementType.FamilyName property exists in 2015 only
    IList<ElementType> viewportTypes = new FilteredElementCollector(doc).OfClass(typeof(ElementType)).Cast<ElementType>()
        .Where(q =>
               q.get_Parameter("Title") != null &&
               q.get_Parameter("Show Title") != null &&
               q.get_Parameter("Show Extension Line") != null &&
               q.get_Parameter("Line Weight") != null &&
               q.get_Parameter("Color") != null &&
               q.get_Parameter("Line Pattern") != null
              ).ToList();

    // create list of ElementIds from list of ElementType objects
    IList<ElementId> viewportTypeIds = new List<ElementId>();
    foreach (Element viewportType in viewportTypes)
    {
        viewportTypeIds.Add(viewportType.Id);
    }
    
    // create list of Viewport Type Element Ids sorted by the integer value of the element ids
    List<ElementId> toDelete = viewportTypeIds.OrderBy(q => q.IntegerValue).ToList();
    
    // Remove the first element in this list so that "Viewport 1" will not be deleted.
    // There seems to be a bug in Revit that prevents deleting "Viewport 1".
    // Even if this viewport is not being used, attempting to delete it results in an error "Deleting all open views in a project is not allowed."
    toDelete.RemoveAt(0);
    
    // remove from this list all viewport types that are in use
    foreach (Element viewport in new FilteredElementCollector(doc).OfClass(typeof(Viewport)))
    {
        ElementId typeId = viewport.GetTypeId();
        toDelete.Remove(typeId);
    }
    
    // do the deletion
    using (Transaction t = new Transaction(doc,"Delete Unused Viewport Types"))
    {
        t.Start();
           doc.Delete(toDelete);
        t.Commit();
    }
}

Deleting Unused Viewport Types

If there are unused Viewport Types that you can’t get rid of with Purge Unused, here is an API approach to try. The ElementType class has many subclasses but not one for ViewportType so the FamilyName property is used instead.

public void deleteUnusedViewportTypes()
{
    Document doc = this.ActiveUIDocument.Document;
    
    // get all viewport types
    IList<ElementType> viewportTypes = new FilteredElementCollector(doc).OfClass(typeof(ElementType)).Cast<ElementType>().Where(q => q.FamilyName == "Viewport").ToList();

    // create list of ElementIds from list of ElementType objects
    IList<ElementId> viewportTypeIds = new List<ElementId>();
    foreach (Element viewportType in viewportTypes)
    {
        viewportTypeIds.Add(viewportType.Id);
    }
    
    // remove from this list all viewport types that are in use
    foreach (Element viewport in new FilteredElementCollector(doc).OfClass(typeof(Viewport)))
    {
        ElementId typeId = viewport.GetTypeId();
        viewportTypeIds.Remove(typeId);
    }
    
    // do the deletion
    using (Transaction t = new Transaction(doc,"Delete Unused Viewport Types"))
    {
        t.Start();
        doc.Delete(viewportTypeIds);
        t.Commit();
    }
}

EDIT: Here is a new version with some additional diagnostic information and the opportunity for the user to abort after seeing the list of viewport types to be deleted.

public void deleteUnusedViewportTypes()
{
    Document doc = this.ActiveUIDocument.Document;
    
    // get all viewport types
    IList<ElementType> viewportTypes = new FilteredElementCollector(doc).OfClass(typeof(ElementType)).Cast<ElementType>().Where(q => q.FamilyName == "Viewport").ToList();

    // create list of ElementIds from list of ElementType objects
    IList<ElementId> viewportTypeIds = new List<ElementId>();
    // do not try to delete Viewport 1, as it is a special viewport type that Revit does not want deleted
    foreach (Element viewportType in viewportTypes.Where(q => q.Name != "Viewport 1"))
    {
        viewportTypeIds.Add(viewportType.Id);
    }
    
    // remove from this list all viewport types that are in use
    foreach (Element viewport in new FilteredElementCollector(doc).OfClass(typeof(Viewport)))
    {
        ElementId typeId = viewport.GetTypeId();
        viewportTypeIds.Remove(typeId);
    }
    
    // generate list of names of viewports to be deleted
    string viewports = "";
    foreach (ElementId id in viewportTypeIds)
    {
        viewports += doc.GetElement(id).Name + Environment.NewLine;
    }
    
    // show Task Dialog with opportunity for user to cancel the operation
    TaskDialog td = new TaskDialog("Viewports");
    td.MainInstruction = "The following viewports will be deleted";
    td.MainContent = viewports;
    td.CommonButtons = TaskDialogCommonButtons.Ok | TaskDialogCommonButtons.Cancel;
    if (td.Show() != TaskDialogResult.Ok)
        return;
    
    string idsNotDeleted = "";
    // do the deletion
    using (Transaction t = new Transaction(doc,"Delete Unused Viewport Types"))
    {
        t.Start();
        
        foreach (ElementId id in viewportTypeIds)
        {
            try
            {
                doc.Delete(id);
            }
            catch // deletion failed - get the name of the element that could not be deleted
            {
                Element eNotDeleted = doc.GetElement(id);
                idsNotDeleted += eNotDeleted.Name + " " + id.IntegerValue.ToString();
            }
        }
        
        t.Commit();
    }
    
    if (idsNotDeleted != "")
    {
        TaskDialog tdError = new TaskDialog("Error");
        tdError.MainInstruction = "The following elements were not able to be deleted";
        tdError.MainContent = idsNotDeleted;
        tdError.Show();
    }
}

Thanks for voting me an #RTCNA Top 10 Speaker!

Thank you to everyone who attended my class “Maintaining order & preventing chaos with the Revit API” at RTCNA 2014. I am honored to have been voted a Top Ten speaker for the 2nd consecutive year!

If you haven’t been to RTC yet, I highly recommend attending the Europe, Australia, and/or North America editions. RTC Europe will be in Dublin at the end of October – I’m looking forward to being there and hope you will be there too.