Kean Walmsley


  • About the Author
    Kean on Google+

July 2014

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 31    








« Shortening a set of AutoCAD lines using .NET | Main | Quite a weekend »

July 16, 2010

Swapping AutoCAD block attribute order using .NET

A big thanks to Philippe Leefsma, from the DevTech team in Europe, for providing this handy piece of code in a response to an ADN member.

In the last post we saw some code that made use of DBObject.HandOverTo() to maintain identity between an old line and a new one with which we wanted to replace it. This code makes use of this method’s counterpart, DBObject.SwapIdWith(), which works on two database-resident objects (rather than the replacement being in-memory, as is the case with HandOverTo()).

Here’s C# code implementing two commands, to swap the identity (and therefore the order) of two attribute definitions and of two attribute references, respectively:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

 

namespace BlockAttributeSwapping

{

  public class Commands

  {

    [CommandMethod("SAD")]

    static public void SwapAttributeDefinitions()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      // Select a block reference

 

      PromptEntityOptions peo =

        new PromptEntityOptions("\nSelect a block reference:");

      peo.SetRejectMessage("\nMust be block reference...");

      peo.AddAllowedClass(typeof(BlockReference), true);

 

      PromptEntityResult per = ed.GetEntity(peo);

      if (per.Status != PromptStatus.OK)

        return;

 

      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // Open the block reference and its connected BTR

 

        BlockReference br =

          (BlockReference)tr.GetObject(

            per.ObjectId,

            OpenMode.ForRead

          );

 

        BlockTableRecord btr =

          (BlockTableRecord)tr.GetObject(

            br.BlockTableRecord,

            OpenMode.ForRead

          );

 

        // If the block definition has attribute definitions...

 

        if (btr.HasAttributeDefinitions)

        {

          // We want to find the first two

 

          ObjectId attId1 = ObjectId.Null;

          ObjectId attId2 = ObjectId.Null;

 

          // Loop through and get them

 

          // (We could clearly extend this to work differently,

          // picking up attributes by name.)

 

          foreach (ObjectId id in btr)

          {

            DBObject obj = tr.GetObject(id, OpenMode.ForRead);

 

            if (obj is AttributeDefinition)

            {

              if (attId1 == ObjectId.Null)

                attId1 = id;

 

              else

              {

                attId2 = id;

                break;

              }

            }

          }

 

          // If we have to attribute definitions...

 

          if (attId1 != ObjectId.Null && attId2 != ObjectId.Null)

          {

            // Open the first and swap it with the second

 

            AttributeDefinition ad =

              (AttributeDefinition)tr.GetObject(

                attId1,

                OpenMode.ForWrite

              );

 

            ad.SwapIdWith(attId2, true, true);

 

            ed.WriteMessage(

              "\nOrder of first two attribute definitions swapped."

            );

          }

 

          // Don't forget to commit the transaction

 

          tr.Commit();

        }

      }

    }

 

    [CommandMethod("SAR")]

    static public void SwapAttributeReferences()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      // Select a block reference

 

      PromptEntityOptions peo =

        new PromptEntityOptions("\nSelect a block reference:");

      peo.SetRejectMessage("\nMust be block reference...");

      peo.AddAllowedClass(typeof(BlockReference), true);

 

      PromptEntityResult per = ed.GetEntity(peo);

      if (per.Status != PromptStatus.OK)

        return;

 

      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // This time we just open the block reference

 

        BlockReference br =

          (BlockReference)tr.GetObject(

            per.ObjectId,

            OpenMode.ForRead

          );

 

        // If the block reference has attribute references...

 

        if (br.AttributeCollection.Count > 1)

        {

          // Once again we just want the first two

 

          // (We could clearly extend this to work differently,

          // picking up attributes by name.)

 

          ObjectId attId1 = br.AttributeCollection[0];

          ObjectId attId2 = br.AttributeCollection[1];

 

          // Open the first and swap it with the second

 

          AttributeReference ar =

            (AttributeReference)tr.GetObject(

              attId1,

              OpenMode.ForWrite

            );

 

          ar.SwapIdWith(attId2, true, true);

 

          ed.WriteMessage(

            "\nOrder of first two attribute references swapped."

          );

        }

 

        // Don't forget to commit the transaction

 

        tr.Commit();

      }

    }

  }

}

Here’s what happens when we run the commands with a simple block containing two attributes:

Ordered attributes

When we edit the attributes by double-clicking one of them in the block, we see the initial order, as expected:

Editing attributes with standard order

If we then swap the order of the attribute references using the SAR command, we see the order reversed when we next edit the attributes:

Editing attributes after swapping their order

The position of the attributes in the drawing is not affected, however, so don’t expect that to change using either of the commands defined in this post.

To see the effect of swapping the order of the attribute definitions in the block table record, start by inserting the block, then run the SAD command and insert the block again:

Command: INSERT

Specify insertion point or [Basepoint/Scale/X/Y/Z/Rotate]:

Enter attribute values

First value <First>:

Second value <Second>:

Command: SAD

Order of first two attribute definitions swapped.

Select a block reference:

Command: INSERT

Specify insertion point or [Basepoint/Scale/X/Y/Z/Rotate]:

Enter attribute values

Second value <Second>:

First value <First>:

You see the order of the attribute definitions has now been swapped, too.

This technique could clearly be extended to swap different attributes – perhaps those selected by name – but at least this code demonstrates the overall approach for swapping attribute order in AutoCAD.

blog comments powered by Disqus

10 Random Posts