Exploding nested AutoCAD blocks using .NET

Some time ago I posted about how to use Entity.Explode() to do something similar to AutoCAD's EXPLODE command. At the time it was mentioned in the comments that BlockReference.ExplodeToOwnerSpace() had some relative benefits, but it's taken me some time to code up a simple sample to show how you might use it (Patrick's recent comment reminded me I ought to, though).

Anyway, to end the week I thought I'd throw together a quick sample. BlockReference.ExplodeToOwnerSpace() doesn't return a list of created objects, so I opted to capture this using a Database.ObjectAppended event handler and then recursively call our custom ExplodeBlock() function for any nested blocks that get created. We also then erase the originating entity (or entities, if called recursively), just as the EXPLODE command might.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

 

namespace Explosions

{

  public class Commands

  {

    [CommandMethod("EB")]

    public void ExplodeBock()

    {

      var doc = Application.DocumentManager.MdiActiveDocument;

      if (doc == null)

        return;

      var ed = doc.Editor;

      var db = doc.Database;

 

      // Ask the user to select the block

 

      var peo = new PromptEntityOptions("\nSelect block to explode");

      peo.SetRejectMessage("Must be a block.");

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

 

      var per = ed.GetEntity(peo);

 

      if (per.Status != PromptStatus.OK)

        return;

 

      using (var tr = db.TransactionManager.StartTransaction())

      {

        // Call our explode function recursively, starting

        // with the top-level block reference

        // (you can pass false as a 4th parameter if you

        // don't want originating entities erased)

 

        ExplodeBlock(tr, db, per.ObjectId);

 

        tr.Commit();

      }

    }

 

    private void ExplodeBlock(

      Transaction tr, Database db, ObjectId id, bool erase = true

    )

    {

      // Open out block reference - only needs to be readable

      // for the explode operation, as it's non-destructive

 

      var br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);

 

      // We'll collect the BlockReferences created in a collection

 

      var toExplode = new ObjectIdCollection();

 

      // Define our handler to capture the nested block references

 

      ObjectEventHandler handler =

        (s, e) =>

        {

          if (e.DBObject is BlockReference)

          {

            toExplode.Add(e.DBObject.ObjectId);

          }

        };

 

      // Add our handler around the explode call, removing it

      // directly afterwards

 

      db.ObjectAppended += handler;

      br.ExplodeToOwnerSpace();

      db.ObjectAppended -= handler;

 

      // Go through the results and recurse, exploding the

      // contents

 

      foreach (ObjectId bid in toExplode)

      {

        ExplodeBlock(tr, db, bid, erase);

      }

 

      // We might also just let it drop out of scope

 

      toExplode.Clear();

 

      // To replicate the explode command, we're delete the

      // original entity

 

      if (erase)

      {

        br.UpgradeOpen();

        br.Erase();

        br.DowngradeOpen();

      }

    }

  }

}

That's it for this week. Monday is a holiday in Neuchatel, so I'll be back online on Tuesday. And then on Wednesday I'm heading to TEDxCERN – which promises to be really cool. Can't wait!

2 responses to “Exploding nested AutoCAD blocks using .NET”

  1. Alexander Rivilis Avatar

    Hi, Kean!

    Not 'BlockReference.ExplodeToOwnerBlock' but 'BlockReference.ExplodeToOwnerSpace'

    1. Hi Alexander,

      Well spotted! Got it wrong more than once in the text, but at least the code was correct. 🙂

      Do let me know if you spot any other errors.

      Thanks & regards,

      Kean

      1. Anthony Rautio Avatar

        How do you keep objects in an array that are within the block from changing location after explode?

        1. Hi Anthony,

          Please ask your support questions via the AutoCAD .NET forum.

          Thanks,

          Kean

  2. Is this retains the individual blocks XData? because if we use the blockreference.Explode(), All XData related to that blocks are missing.

    1. Hi Gokul,

      There's nothing in this code that does special handling of XData, so I don't expect it to be different. Please post your follow-up technical support questions to the AutoCAD .NET forum.

      Thank you,

      Kean

Leave a Reply to Anthony Rautio Cancel reply

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