Creating an AutoCAD layer using .NET

Sometimes I receive a question which makes me think "I must have posted something that shows that by now, surely?" and yet I can't find it. So please accept my apologies if this post is redundant and I'm just repeating myself. ๐Ÿ™‚

Here's the question that had me thinking:

I don't know how may I create a new layer in drawing.

And here's some code I threw together to show this. It defines a simple command called CL which creates a layer with the name proposed by the user, after validating the name using the SymbolUtilityServices namespace (which I admit not to having used before, at least not via the .NET layer). It also sets the colour-index of the layer to an auto-incremented value, and sets the current layer to the newly-created one (so it shows up nicely in AutoCAD's user interface).

Here's the C# code:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Colors;

 

namespace LayerCreation

{

  public class Commands

  {

    // For fun let's assign each new layer with a new colour

 

    static short _colorIndex = 0;

 

    [CommandMethod("CL")]

    public void CreateLayer()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // Get the layer table from the drawing

 

        LayerTable lt =

          (LayerTable)tr.GetObject(

            db.LayerTableId,

            OpenMode.ForRead

          );

 

        // Check the layer name, to see whether it's

        // already in use

 

        PromptStringOptions pso =

          new PromptStringOptions(

            "\nEnter new layer name: "

          );

        pso.AllowSpaces = true;

 

        // A variable for the layer name

 

        string layName = "";

 

        do

        {

          PromptResult pr = ed.GetString(pso);

 

          // Just return if the user cancelled

          // (will abort the transaction as we drop out of the using

          // statement's scope)

 

          if (pr.Status != PromptStatus.OK)

            return;

 

          try

          {

            // Validate the provided symbol table name

 

            SymbolUtilityServices.ValidateSymbolName(

              pr.StringResult,

              false

            );

 

            // Only set the layer name if it isn't in use

 

            if (lt.Has(pr.StringResult))

              ed.WriteMessage(

                "\nA layer with this name already exists."

              );

            else

              layName = pr.StringResult;

          }

          catch

          {

            // An exception has been thrown, indicating the

            // name is invalid

 

            ed.WriteMessage(

              "\nInvalid layer name."

            );

          }

 

        } while (layName == "");

 

        // Create our new layer table record...

 

        LayerTableRecord ltr = new LayerTableRecord();

 

        // ... and set its properties

 

        ltr.Name = layName;

        ltr.Color =

          Color.FromColorIndex(ColorMethod.ByAci, _colorIndex);

 

        // Add the new layer to the layer table

 

        lt.UpgradeOpen();

        ObjectId ltId = lt.Add(ltr);

        tr.AddNewlyCreatedDBObject(ltr, true);

 

        // Set the layer to be current for this drawing

 

        db.Clayer = ltId;

 

        // Commit the transaction

 

        tr.Commit();

 

        // Report what we've done

 

        ed.WriteMessage(

          "\nCreated layer named \"{0}\" with " +

          "a color index of {1}.",

          layName, _colorIndex++

        );

      }

    }

  }

}

When we run the CL command, the user will be asked for a layer name which โ€“ assuming it's valid and isn't already used in the current drawing โ€“ will be used to name the newly created layer. If the name is invalid or already in use, the code will loop until valid and usable name is provided (or the user cancels).

Command: CL

Enter new layer name: 1

Created layer named "1" with a color index of 0.

Command: CL

Enter new layer name: 1

A layer with this name already exists.

Enter new layer name: 0

A layer with this name already exists.

Enter new layer name: *

Invalid layer name.

Enter new layer name: 2

Created layer named "2" with a color index of 1.

Command: CL

Enter new layer name: 3

Created layer named "3" with a color index of 2.

14 responses to “Creating an AutoCAD layer using .NET”

  1. AutoDesk has an online document on .Net now, so answer can be found there: docs.autodesk.com/ACD/2010/ENU/AutoCAD%20.NET%20Developer's%20Guide/index.html

  2. This is true - and a great point to mention - although this post does show the technique to validate the layer name. Which may or not be of significance, depending on where the name is coming from.

    Kean

  3. Would be interesting to see how to add a linetype
    to layer relatively to metric/imperial units
    Just a thought
    if you have a time ๐Ÿ™‚

    Oleg

  4. Hi Oleg,

    Sounds like an interesting topic (although I have to admit I haven't spent much time worrying about unit conversion, myself). If you could send me an email with more information on how this would work, I'll see whether it's something I can address in a blog post.

    Regards,

    Kean

  5. Here's one that could probably do with a makeover ๐Ÿ™‚
    1
    (Need to be a member to see attachments, though anyone can read.)

    Kerry Brown

  6. Please Help Me
    how to update .DXF File Using VB.NET

  7. Please submit support questions via the ADN website (if you're a member) or to the AutoCAD .NET Discussion Group (otherwise).

    In this case you should read the DXF file into a Database object (whether using AutoCAD or RealDWG), perform your update and save it back.

    Kean

  8. Thanks to you and thanks to Kerry Brown as well

    And much thanks for your nice blog ๐Ÿ™‚

    Regards,

    Oleg

    ~'J'~

  9. isnt it easyer to just write document.layers.add("name");
    it does nothing when duplicated
    and invalid layer names should be checked earlyer too

  10. Kean Walmsley Avatar

    You can certainly use COM Interop to do things "more easily". The .NET API tends to be lower level, in many ways, and so provides more flexibility and also needs more care. This post is about showing the appropriate steps for using that API, not necessarily about showing the simplest approach.

    Kean

  11. Hi Kean, I've one question, I'm trying to delete some layers in a drawing, right now I'm accessing the database, layertable and I get the records. At this time I can turn on and off the layers and it works properly, but when I try to delete this layers instead of turn them off, the layer gets deleted but the content of the layer goes to the '0' layer.

    the method I'm using is "specLayer.Erase(true);", I've been searching across the web and what I see is that you can't delete the actual layer, '0' layer, not empty layer and freeze layers. I think that my problem is that my layers are not empty, is there a way to remove all the content of the layer so that after this I delete the layer??

    Hope you can help me, by the way I'm using AutoCAD 2013 and C#

    Thanks!

    1. Hi Daniel,

      This is a support question... please ask these via the discussion groups, in future.

      You shouldn't just erase a layer with content: you should call Database.Purge() to check whether there are dependencies on it. If there are, you can certainly search the drawing for entities that use it and change their layer or erase them (whichever makes most sense). Then you should be able to erase the layer itself.

      Regards,

      Kean

  12. The above written code works fine when I am creating a single layer. It fails when creating multiple layers.
    Here's my code which fails at,
    LayerTable layerTable = (LayerTable)this.transaction.GetObject(this.database.LayerTableId, OpenMode.ForRead);

    Code:
    ////////////////////////////////////////////////////////////////////////////////////////////////
    foreach (LayerAttributeColor item in layerColorAttributeValues)
    {
    LayerTable layerTable = (LayerTable)this.transaction.GetObject(this.database.LayerTableId, OpenMode.ForRead);
    if (!layerTable.Has(item.LayerName))
    {
    LayerTableRecord ltr = new LayerTableRecord();

    // ... and set its properties
    ltr.Name = item.LayerName;
    ltr.Color = Autodesk.AutoCAD.Colors.Color.FromRgb(255, 0, 0);

    // Add the new layer to the layer table
    layerTable.UpgradeOpen();
    ObjectId ltId = layerTable.Add(ltr);
    layerTable.DowngradeOpen();

    this.transaction.AddNewlyCreatedDBObject(ltr, true);

    // Set the layer to be current for this drawing
    //this.database.Clayer = ltId;
    // Commit the transaction
    this.transaction.Commit();
    ltr.Dispose();
    }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////

    The exception message reads as,
    "Operation is not valid due to the current state of the object".

    What's the correct way to close the layertable?
    Please advise.

    1. I don't have time to provide support: please post your code to the AutoCAD .NET forum.

      Kean

Leave a Reply to Luis Daniel Cancel reply

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