#RTCEUR API Wish #1: Purging Types and Families

The first wish granted from Porto is for Phil who wished for “a solution to purging unused Revit elements from a Revit model”. Different elements need to be purged in different ways. This code will clean up unused system and loadable families and their types.

How are you wishing to make Revit better?

purge-browser

The “RollbackIfErrorOccurs” section is used to handle the case where deleting a wall type would result in this error.

last-type-in-system-family

public void purgeFamiliesAndTypes()
{
    Document doc = this.ActiveUIDocument.Document;
    
    // List of categories whose families will be purged
    List<int> categoriesToPurge = new List<int>();
    categoriesToPurge.Add((int)BuiltInCategory.OST_StructuralFraming);
    categoriesToPurge.Add((int)BuiltInCategory.OST_Walls);

    List<ElementId> typesToDelete = new List<ElementId>();

    // Check all element types whose category is contained in the category list	
    foreach (ElementType et in new FilteredElementCollector(doc)
             .OfClass(typeof(ElementType))
             .Cast<ElementType>()
             .Where(q => q.Category != null && 
                    categoriesToPurge.Contains(q.Category.Id.IntegerValue)))
    {
        // if there are no elements with this type, add it to the list for deletion
        if (new FilteredElementCollector(doc)
            .WhereElementIsNotElementType()
            .Where(q => q.GetTypeId() == et.Id).Count() == 0)
        {
            typesToDelete.Add(et.Id);
        }
    }
        
    using (TransactionGroup tg = new TransactionGroup(doc, "Purge families"))
    {
        tg.Start();
        foreach (ElementId id in typesToDelete)
        {    
            using (Transaction t = new Transaction(doc, "delete type"))
            {
                // Do not delete type if it would result in error such as
                // "Last type in system family "Stacked Wall" cannot be deleted."
                FailureHandlingOptions failOpt = t.GetFailureHandlingOptions();
                failOpt.SetClearAfterRollback(true);
                failOpt.SetFailuresPreprocessor(new RollbackIfErrorOccurs());
                t.SetFailureHandlingOptions(failOpt);
                
                t.Start();
                try
                {
                    doc.Delete(id);
                }
                catch
                {}
                t.Commit();
            }    
        }
        
        // Delete families that now have no types
        IList<ElementId> familiesToDelete = new List<ElementId>();    
        foreach (Family family in new FilteredElementCollector(doc)
            .OfClass(typeof(Family))
            .Cast<Family>()
            .Where(q => categoriesToPurge.Contains(q.FamilyCategory.Id.IntegerValue)))
        {
            // add family to list if there are no instances of any type of this family
            if (new FilteredElementCollector(doc)
                .OfClass(typeof(FamilyInstance))
                .Cast<FamilyInstance>()
                .Where(q => q.Symbol.Family.Id == family.Id)
                .Count() == 0)
            {
                familiesToDelete.Add(family.Id);
            }
        }
        
        using (Transaction t = new Transaction(doc, "delete families with no types"))
        {
            t.Start();
            doc.Delete(familiesToDelete);
            t.Commit();
        }
        
        tg.Assimilate();
    }
}

public class RollbackIfErrorOccurs : IFailuresPreprocessor
{
    public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
    {
        // if there are any failures, rollback the transaction
        if (failuresAccessor.GetFailureMessages().Count > 0)
        {
            return FailureProcessingResult.ProceedWithRollBack;
        }
        else
        {
            return FailureProcessingResult.Continue;
        }
    }
}        
Advertisements

2 thoughts on “#RTCEUR API Wish #1: Purging Types and Families

  1. Hi,

    I’ve tried to use this code in a macro and an addin, but I can’t get it to work.
    I’m not getting any exceptions, on build. It’s just not doing anything and I’m not sure how to debug it? I’ve tested it in 2016 & 2017.1 with no results.

    Any ideas?

    Best Regards,

    Maciej

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s