Moving entities from one AutoCAD layer to another using .NET

Firstly I should apologise to those readers using RSS to access this site: I've been playing around with the configuration, to integrate FeedBurner but also to switch from publishing entire articles via RSS to publishing introductions - my posts are just too long, which seems to cause a problem for some RSS readers. So you may have received multiple versions of the same articles for the last few weeks - sorry about that.

For those of you who have not yet subscribed via RSS - please see the new options in the side-bar on the left: it should now be simpler for you to use your favourite RSS reader to pull down excerpts of the content I publish, rather than checking the site itself.

OK, now onto the real content. I had this question come in from António Rodrigues, an engineering student from Portugal:

I'm doing a project at school about hydraulics calculations, where i have get some data from AutoCAD. [...] I need to get all the objects from a single layer in the drawing, so i can use them to perform the calculations needed.

I put together some code for Antonio which uses Editor.SelectAll() with an appropriate SelectionFilter to get the list of entities on a particular layer. Just for fun I then extended the code to allow the user to enter a new layer name for these entities to be moved to.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

namespace LayerTools

{

  public class Commands

  {

    [CommandMethod("CL")]

    public void ChangeLayerOfEntitiess()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

      // Ask the user for the layer name, allowing

      // spaces to be entered

      PromptStringOptions pso =

        new PromptStringOptions(

          "\nEnter name of layer to search for: "

        );

      pso.AllowSpaces = true;

      PromptResult pr =

        ed.GetString(pso);

      if (pr.Status != PromptStatus.OK)

        return;

      string layerName = pr.StringResult;

      // We won't validate whether the layer exists -

      // we'll just see what's returned by the selection.

      TypedValue[] tvs = new TypedValue[1];

      tvs[0] =

        new TypedValue((int)DxfCode.LayerName, layerName);

      SelectionFilter sf = new SelectionFilter(tvs);

      PromptSelectionResult psr = ed.SelectAll(sf);

      int count = 0;

      if (psr.Status == PromptStatus.OK)

        count = psr.Value.Count;

      if (psr.Status == PromptStatus.OK ||

          psr.Status == PromptStatus.Error)

      {

        // Display the count of entities on that layer

        ed.WriteMessage(

          "\nFound {0} entit{1} on layer \"{2}\".",

          count,

          count == 1 ? "y" : "ies",

          layerName

        );

        // If there are some on this layer,

        // prompt for the layer to move them to

        if (count > 0)

        {

          pso.Message =

            "\nEnter new layer for these entities " +

            "or return to leave them alone: ";

          pr =

            ed.GetString(pso);

          if (pr.Status != PromptStatus.OK ||

              pr.StringResult == "")

            return;

          string newLayerName = pr.StringResult;

          Transaction tr =

            db.TransactionManager.StartTransaction();

          using (tr)

          {

            // This time we do check whether

            // the layer exists

            LayerTable lt =

              (LayerTable)tr.GetObject(

                db.LayerTableId,

                OpenMode.ForRead

              );

            if (!lt.Has(newLayerName))

              ed.WriteMessage("\nLayer not found.");

            else

            {

              int changedCount = 0;

              // We have the layer table open, so let's

              // get the layer ID and use that

              ObjectId lid = lt[newLayerName];

              foreach (ObjectId id in psr.Value.GetObjectIds())

              {

                Entity ent =

                  (Entity)tr.GetObject(id, OpenMode.ForWrite);

                ent.LayerId = lid;

                // Could also have used:

                //  ent.Layer = newLayerName;

                // but this way is more efficient and cleaner

                changedCount++;

              }

              ed.WriteMessage(

                "\nChanged {0} entit{1} from " +

                "layer \"{2}\" to layer \"{3}\".",

                changedCount,

                changedCount == 1 ? "y" : "ies",

                layerName,

                newLayerName

              );

            }

            tr.Commit();

          }

        }

      }

    }

  }

}

Here's what happens when you run the CL command and use it to move entities from the "Dim" layer to "My new layer":

Command: CL

Enter name of layer to search for: Dim

Found 14 entities on layer "Dim".

Enter new layer for these entities or return to leave them alone: My new layer

Changed 14 entities from layer "Dim" to layer "My new layer".

10 responses to “Moving entities from one AutoCAD layer to another using .NET”

  1. It is an interesting and useful code. Can you make it a routine that can be run from command line.

  2. I'd suggest checking out this post for information on how to do this.

    Regards,

    Kean

  3. Is there any change to use Editor.SelectAll for a document that is not the currently active document (e.g. necessary if actions are taken during autosave of a document that is in the background) ?

  4. Editor.SelectAll() requires the document to be open and active in the editor, as far as I'm aware. You can gather a list of objects to work upon by iterating through the contents of a non-editor resident drawing, however.

    Kean

  5. hello,

    at first thanks for the code, it is very useful.

    i don't know if this is the most appropriate thread but:

    I´m trying to delete a layer as an entity and i get the error eCannotBeErasedByCaller in Autodesk.AutoCAD.DatabaseServices.DBObject.Erase(boolean erasing),

    i found some lisp scripts to do it but i prefer do it in c# to distribute one single file .dll.
    I found laydel command but it prompts me to input an entity into the layer

    Thanks,

    Miguel

  6. Hi Miguel,

    In future if you have support requests please submit them via ADN, if you're a member, or to the AutoCAD .NET Discussion Group, otherwise. I generally don't have time to provide support unrelated to specific posts.

    I haven't come across that error (at least as far as I can recall). I suggest looking at calling Database.Purge() on the layer (see this post to understand how purge() works). If that doesn't help then please post your code to the discussion group linked to above.

    Regards,

    Kean

  7. Hello Kean,

    sorry for answering late, I'm in the ADN now, and the problem was that i can´t delete the current layer, so i'll change the db.Clayer.

    Thanks,
    Miguel

  8. Kean Walmsley Avatar

    Aha, great - thanks for letting me know, Miguel.

    Kean

  9. Sumedh Karandikar Avatar

    Hi,
    We want to read a table Bill of Material information written in a particular later. Although we can read the layer but can not read any information from it. It is more like text entered in a Layer. How can we read it in c#

  10. Hi,

    Please post your question to the AutoCAD .NET Discussion Group.

    Thank you,

    Kean

Leave a Reply to Kean Walmsley Cancel reply

Your email address will not be published. Required fields are marked *