Author Topic: Select all instances of a dynamic block  (Read 2372 times)

0 Members and 1 Guest are viewing this topic.

kaefer

  • Guest
Select all instances of a dynamic block
« on: September 20, 2012, 05:28:59 AM »
This topic was recently  at Kean's blog. I do not mean to criticize his approach, which works by generating a selection filter comprising all of the block's names, anonymous or otherwise.

My intent is to demonstrate the use of the SelectionAdded event handler for this problem. Then it's not names, but only an ObjectId which has to be checked for equality.

Code - C#: [Select]
  1. // Variation on how to select all instances of a Dynameic block, originally by Kean Walmsley
  2. // http://through-the-interface.typepad.com/through_the_interface/2012/09/creating-a-selection-filter-that-finds-dynamic-blocks-in-autocad-using-net.html
  3.  
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.Runtime;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.EditorInput;
  8. using System.Collections.Generic;
  9.  
  10. namespace EntitySelection
  11. {
  12.     public class Commands
  13.     {
  14.         [CommandMethod("SDB")]
  15.         static public void SelectDynamicBlocks()
  16.         {
  17.             var doc = Application.DocumentManager.MdiActiveDocument;
  18.             var ed = doc.Editor;
  19.  
  20.             var pso =
  21.               new PromptStringOptions(
  22.                 "\nName of dynamic block to search for"
  23.               );
  24.             pso.AllowSpaces = true;
  25.  
  26.             var pr = ed.GetString(pso);
  27.  
  28.             if (pr.Status != PromptStatus.OK)
  29.                 return;
  30.  
  31.             string blkName = pr.StringResult;
  32.  
  33.             List<string> blkNames = new List<string>();
  34.             blkNames.Add(blkName);
  35.  
  36.             PromptSelectionResult psr;
  37.             using (var tr = doc.TransactionManager.StartTransaction())
  38.             {
  39.                 var bt =
  40.                   (BlockTable)tr.GetObject(
  41.                     doc.Database.BlockTableId,
  42.                     OpenMode.ForRead
  43.                   );
  44.  
  45.                 // Start by getting access to our block, if it exists
  46.  
  47.                 if (!bt.Has(blkName))
  48.                 {
  49.                     ed.WriteMessage(
  50.                       "\nCannot find block called \"{0}\".", blkName
  51.                     );
  52.                     return;
  53.                 }
  54.  
  55.                 // Skip the test for IsDynamicBlock, since this will work
  56.                 // for standard blocks regardless
  57.  
  58.                 // Define an event handler in the current scope
  59.  
  60.                 SelectionAddedEventHandler handler =
  61.                     delegate(object sender, SelectionAddedEventArgs e)
  62.                     {
  63.                         foreach (int i in e.AddedObjects.GetIndicesToRemove(bt[blkName]))
  64.                             e.Remove(i);
  65.                     };
  66.  
  67.                 // Select anonymous "`**" and regular "*" block references
  68.  
  69.                 SelectionFilter sf =
  70.                     new SelectionFilter(new TypedValue[] {
  71.                         new TypedValue(
  72.                             (int)DxfCode.BlockName, "`**,*")});
  73.  
  74.                 ed.SelectionAdded += handler;
  75.                 try
  76.                 {
  77.                     psr = ed.SelectAll(sf);
  78.                 }
  79.                 finally
  80.                 {
  81.                     ed.SelectionAdded -= handler;
  82.                 }
  83.                 tr.Commit();
  84.             }
  85.  
  86.             if (psr == null || psr.Value == null)
  87.             {
  88.                 ed.WriteMessage("\nNo entities found. ");
  89.                 return;
  90.             }
  91.             ed.WriteMessage(
  92.               "\nFound {0} entit{1}.",
  93.               psr.Value.Count,
  94.               (psr.Value.Count == 1 ? "y" : "ies")
  95.             );
  96.         }
  97.     }
  98.     static class IEnumerable
  99.     {
  100.         // Extension to SelectionSet which opens all block references that pass
  101.         // the SelectionFilter. Returns a sequence of integer indices corresponding
  102.         // to the block's position in the SelectionSet, which will remove them from it.
  103.         // Don't return any index for a block refences whose DynamicBlockTableRecord
  104.         // property isn't equal to the ObjectId of our wanted block's prototype definition
  105.  
  106.         public static IEnumerable<int> GetIndicesToRemove(this SelectionSet added, ObjectId btrOid)
  107.         {
  108.             int i = 0;
  109.             foreach (SelectedObject so in added)
  110.             {
  111.                 var br =
  112.                     (BlockReference)so.ObjectId.GetObject(OpenMode.ForRead);
  113.                 if (br.DynamicBlockTableRecord != btrOid)
  114.                     yield return i;
  115.                 i++;
  116.             }
  117.         }
  118.     }
  119. }
  120.