Through the Interface: Creating a legend of AutoCAD drawings using .NET

May 2015

Sun Mon Tue Wed Thu Fri Sat
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30


« Using the Microsoft Kinect SDK to sweep segmented solids inside AutoCAD | Main | Recorded AutoCAD .NET training available for download »

October 27, 2011

Creating a legend of AutoCAD drawings using .NET

This interesting question came up in our discussion forums:

Does anyone have a routine that will insert all the drawings from a single folder into one drawing to create a legend sheet? I'm trying to document the company's various blocks and details for dissemination amongst several offices.

The simplest – and most elegant, in my opinion – approach for addressing this requirement is via the Table object, which allows you to include block thumbnails in each of its cells. So we would need to import the various drawings into the current drawing as blocks, and then point the various cells of the table object at each of them, in turn. Thankfully I could borrow a good amount of the code to do this from these previous posts.

Here’s the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;

using System.IO;

using System.Linq;


namespace MythsAndLegends


  public class Commands



    public void CreateLegend()


      Document doc =


      Database db = doc.Database;

      Editor ed = doc.Editor;


      // Ask the user to select the drawings to list in the table


      OpenFileDialog ofd =

        new OpenFileDialog(

          "Select drawings to add to legend",







      System.Windows.Forms.DialogResult dr = ofd.ShowDialog();


      if (dr != System.Windows.Forms.DialogResult.OK)



      // Get the list of filenames and say how many were selected


      string[] names = ofd.GetFilenames();


        "\n{0} files selected.", names.Length



      // If we have some selected, we'll create a table


      if (names.Length > 0)


        int numRows, numCols;


        // If only one was selected, we know the table will

        // be 1x1


        if (names.Length == 1)


          numRows = 1;

          numCols = 1;




          // Otherwise we prompt for the number of columns


          PromptIntegerOptions opts =

            new PromptIntegerOptions(

              "\nEnter number of columns: "



          opts.LowerLimit = 1;

          opts.UpperLimit = names.Length;

          opts.DefaultValue = 1;

          opts.UseDefaultValue = true;


          PromptIntegerResult pir = ed.GetInteger(opts);


          if (pir.Status != PromptStatus.OK)



          // Get whether to start at the top or the bottom


          PromptKeywordOptions pko =

            new PromptKeywordOptions(

              "\nPopulate from the top or from the bottom?"


          pko.AllowNone = true;



          pko.Keywords.Default = "Top";


          PromptResult pkr = ed.GetKeywords(pko);


          bool fromTop = (pkr.StringResult == "Top");


          // Get whether to start at the top or the bottom


          pko =

            new PromptKeywordOptions(

              "\nList alphabetically or in selected order?"


          pko.AllowNone = true;



          pko.Keywords.Default = "Alphabetically";


          pkr = ed.GetKeywords(pko);


          bool sort = (pkr.StringResult == "Alphabetically");


          // And the insertion point of the table


          PromptPointResult pr =

            ed.GetPoint("\nEnter table insertion point: ");


          if (pr.Status == PromptStatus.OK)


            Transaction tr =



            using (tr)


              // Use constants for the cell dimensions


              const int cellWidth = 3;

              const int cellHeight = 3;


              // Create the table


              Table tb = new Table();

              tb.TableStyle = db.Tablestyle;


              // We can calculate the number of rows based on

              // the number of cells and the number of columns


              numCols = pir.Value;

              numRows = (names.Length / numCols) + 1;


              // We'll add in our custom columns and rows


              if (numCols > 0)


                tb.InsertColumns(1, cellWidth, numCols);


              if (numRows > 0)


                tb.InsertRows(1, cellHeight, numRows);



              // And then delete the original row/column

              // that comes with the blank table


              tb.DeleteRows(0, 1);

              tb.DeleteColumns(0, 1);


              tb.Position = pr.Value;


              if (sort)


                names = names.OrderBy(x => x).ToArray<string>();



              // Loop through the names, adding them to the table


              for (int i = 0; i < names.Length; i++)


                string blockName = "";




                  // Use a Database to insert a block for each

                  // drawing into the current drawing


                  using (Database src = new Database(false, true))


                    // First we read in the DWG



                      names[i], FileShare.Read, true, ""



                    // Take the name of the file without the

                    // extension


                    blockName =



                    // Check whether it works as a symbol table

                    // name (will thrown an exception if not)



                      blockName, false



                    // Insert our drawing as a block (which

                    // will take the modelspace)


                    ObjectId blockId =

                      db.Insert(blockName, src, false);


                    // Calculate the row and column for this item

                    // If from the top: we just divide by the

                    // number of columns to get the row

                    // If from the bottom, subtract from

                    // the total rows


                    int row =

                      (fromTop ?

                        i / numCols :

                        numRows - (i / numCols + 1)



                    // The column is just the modulus remainder


                    int col = i % numCols;


                    // Insert the block as the contents of our cell


                    Cell cell = tb.Cells[row, col];


                    cell.Contents[0].BlockTableRecordId =




                catch (System.Exception ex)



                    "\nCould not add \"{0}\": {1}",

                    blockName, ex.Message






              // Finally we add our table to modelspace


              BlockTable bt =






              BlockTableRecord btr =






              tr.AddNewlyCreatedDBObject(tb, true);









When we run the LEGEND command, we get asked to select some drawings:

Selecting a set of drawing files

We then get prompted with the number of drawings selected and get asked to provide some additional information to determine how the table gets created. We’ll run the command twice, selecting the same set of AutoCAD sample drawings but using 3 and 4 columns, populating the two tables from the top and the bottom respectively.

Command: LEGEND

13 files selected.

Enter number of columns <1>: 3

Populate from the top or from the bottom? [Top/Bottom] <Top>: Top

List alphabetically or in selected order? [Alphabetically/Selected]

<Alphabetically>: Alphabetically

Enter table insertion point:


[Dump of block imports deleted...]


Command: LEGEND

13 files selected.

Enter number of columns <1>: 4

Populate from the top or from the bottom? [Top/Bottom] <Top>: Bottom

List alphabetically or in selected order? [Alphabetically/Selected]

<Alphabetically>: Alphabetically

Enter table insertion point:


[Dump of block imports deleted...]

We can see that the tables contain the same order of blocks, but the first is wider and was populated from the top-left rather than the bottom-left:Two legend tables created from a folder of drawings

blog comments powered by Disqus


10 Random Posts