Looped Deletion of Elements in 2014

The code below would seem like a reasonable way to delete a set of elements returned by the FilteredElementCollector

public void deleteImportsNotLinks_Does_Not_Work_In_2014()
{
    Document doc = this.ActiveUIDocument.Document;
    using (Transaction t = new Transaction(doc,"Delete Imports"))
       {
        t.Start();
        foreach (ImportInstance ii in new FilteredElementCollector(doc)
                 .OfClass(typeof(ImportInstance))
                 .Cast<ImportInstance>()
                 .Where(i => i.IsLinked == false))
        {
            doc.Delete(ii.Id);
        }      
        t.Commit();
   }
}

But if you try this in 2014 you get this error.

Capture

This tells us that the FilteredElementCollector is unhappy because we deleted an element, which changed Revit’s database, which then causes problems when Revit tries to go to the next element that would be returned from the FilteredElementCollector.

The solution is to split the code into two parts

  1. Build a list of the element ids to delete (called ‘toDelete’ in the code sample below)
  2. Delete the elements in this list

Like this:

public void deleteImportsNotLinks()
{
    Document doc = this.ActiveUIDocument.Document;

    IList<ElementId> toDelete = new List<ElementId>();
    foreach (ImportInstance ii in new FilteredElementCollector(doc)
         .OfClass(typeof(ImportInstance))
         .Cast<ImportInstance>()
         .Where(i => i.IsLinked == false))
        {
            toDelete.Add(ii.Id);
        }   

    using (Transaction t = new Transaction(doc,"Delete Imports"))
       {
        t.Start();
        doc.Delete(toDelete);  
        t.Commit();
    }
}

UPDATE: As Philip noted in the comments, this is a good opportunity to use the overload of Document.Delete that takes an ICollection(ElementId) as its input as shown in the updated code sample. Check out the next post for an even fancier way to do this.

Advertisements

6 thoughts on “Looped Deletion of Elements in 2014

  1. HI Harry.

    I believe you can simplify the last loop for deletion by removing the loop altogether and pass in the entire element ID Collector. ie doc.Delete(toDelete); Mind you I haven’t tried it 🙂

    Regards Phillip

  2. This is not an issue specific to Revit or 2014 (although possible an error was not thrown previously). A list should never be changed (add/delete) within a foreach loop. That is obvious when you think about it; the list is changing as it is being parsed. I have had to learn the hard way on more that one occssion, sadly…

  3. Hi.
    I still have DWG-elements in Visibility/Graphic overrides – imported categories. But no matter how hard I try to find the actual elements from the DWG, I cannot find them.
    The code did not remove them unfortunately.

    -k-

  4. I am getting a

    “‘dwg.ThisDocument’ does not contain a definition for ‘ActiveUIDocument’ and no extension method ‘ActiveUIDocument’ accepting a first argument of type ‘dwg.ThisDocument’ could be found (are you missing a using directive or an assembly reference?) (CS1061) – C:\Users\bradym\AppData\Local\Temp\{D490B89C-C871-4520-9FBD-0AC641866225}\Revit\DocHookups2288\1289778560\dwg\Source\dwg\ThisDocument.cs:43,25”

    error. Any idea what when wrong please sir.

    Code below.

    /*
    * Created by SharpDevelop.
    * User: xxxxx
    * Date: xxxxx
    * Time: 3:54 PM
    *
    * To change this template use Tools | Options | Coding | Edit Standard Headers.
    */
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using Autodesk.Revit.DB;
    using Autodesk.Revit.DB.Architecture;
    using Autodesk.Revit.DB.Events;
    using Autodesk.Revit.UI;
    using Autodesk.Revit.UI.Selection;

    namespace dwg
    {
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.DB.Macros.AddInId(“470DEA82-4A6B-409D-8CC1-09C147789541″)]
    public partial class ThisDocument
    {
    private void Module_Startup(object sender, EventArgs e)
    {

    }

    private void Module_Shutdown(object sender, EventArgs e)
    {

    }

    #region Revit Macros generated code
    private void InternalStartup()
    {
    this.Startup += new System.EventHandler(Module_Startup);
    this.Shutdown += new System.EventHandler(Module_Shutdown);
    }
    #endregion
    public void deleteImportsNotLinks()
    {
    Document doc = this.ActiveUIDocument.Document;

    IList toDelete = new List();
    foreach (ImportInstance ii in new FilteredElementCollector(doc)
    .OfClass(typeof(ImportInstance))
    .Cast()
    .Where(i => i.IsLinked == false))
    {
    toDelete.Add(ii.Id);
    }

    using (Transaction t = new Transaction(doc,”Delete Imports”))
    {
    t.Start();
    doc.Delete(toDelete);
    t.Commit();
    }
    }

    }
    }

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