TheSwamp

Code Red => .NET => Topic started by: GILESP on August 23, 2012, 06:02:25 AM

Title: Easy way to get attributes from blocks
Post by: GILESP on August 23, 2012, 06:02:25 AM
I'm working on my first grown up VB.net project, which is a rewrite of a vba script that collects certain attribute values from blocks and tabulates them as a BOM.

I'm struggling to get attribute values from block references - I'm compounded by the issue that whilst most of the attributes are constant, there are cases where they aren't  so I really need to collect all attributes and sort by tag.

My VBA approach used the BlockRef.Getattributes and the BlockRef.GetConstantAttributes method which put everything I needed in a data structure for me.

My VB method for getting attributes differs depending of if it's contant: for non constant attributes I'm using blockref.AttributeCollection statement which then give me a structure containing attributes, very much as per VBA

However for constant attributes, I'm currently having to go to the block definition, and recurse through the contents, isolating attribute definitions and checking if the constant property is true

These are 2 pretty different approaches, and are upsetting my programing mojo a bit - is there one technique that can be used for both types of attribute?

Any thoughts, tips or code fragments would be appreciated..

G
Title: Re: Easy way to get attributes from blocks
Post by: MexicanCustard on August 23, 2012, 07:54:46 AM
blockref.AttributeCollection will return all AttributeReferences associated with the BlockReference this includes any marked as constant.
Title: Re: Easy way to get attributes from blocks
Post by: Kerry on August 23, 2012, 08:06:52 AM
Perhaps ;
Make this .NET forum current and search for AttributeCollection
... you'll probably find a couple of days reading :)
 
Title: Re: Easy way to get attributes from blocks
Post by: GILESP on August 23, 2012, 08:38:25 AM
blockref.AttributeCollection will return all AttributeReferences associated with the BlockReference this includes any marked as constant.

Really? It is not in my case.  Are there conditions in which it doesn't return a attribute reference? Perhaps hidden ones? (they're hidden in my example).


Kerry - have tried the search feature again - you're right, many days reading..  :-o
Title: Re: Easy way to get attributes from blocks
Post by: TheMaster on August 23, 2012, 06:30:09 PM
I'm working on my first grown up VB.net project, which is a rewrite of a vba script that collects certain attribute values from blocks and tabulates them as a BOM.

I'm struggling to get attribute values from block references - I'm compounded by the issue that whilst most of the attributes are constant, there are cases where they aren't  so I really need to collect all attributes and sort by tag.

My VBA approach used the BlockRef.Getattributes and the BlockRef.GetConstantAttributes method which put everything I needed in a data structure for me.

My VB method for getting attributes differs depending of if it's contant: for non constant attributes I'm using blockref.AttributeCollection statement which then give me a structure containing attributes, very much as per VBA

However for constant attributes, I'm currently having to go to the block definition, and recurse through the contents, isolating attribute definitions and checking if the constant property is true

These are 2 pretty different approaches, and are upsetting my programing mojo a bit - is there one technique that can be used for both types of attribute?

Any thoughts, tips or code fragments would be appreciated..

G

Sorry for the C#, me no speak VB  :grin:

Code - C#: [Select]
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using Autodesk.AutoCAD.Runtime;
  7.  
  8. namespace Autodesk.AutoCAD.DatabaseServices
  9. {
  10.    public static class AcDbExtensionMethods
  11.    {
  12.       static RXClass attDefClass = RXClass.GetClass( typeof( AttributeDefinition ) );
  13.  
  14.       // Requires a transaction (not an OpenCloseTransaction) to be active when called:
  15.       // Returns an enumeration of all AttributeDefinitions whose Constant property is
  16.       // true, and all AttributeReferences attached to the block reference.
  17.  
  18.       public static IEnumerable<DBText> GetAttributes( this BlockReference blockRef )
  19.       {
  20.          Transaction tr = blockRef.GetTransaction();
  21.          BlockTableRecord btr = (BlockTableRecord) blockRef.DynamicBlockTableRecord.GetObject( OpenMode.ForRead );
  22.          if( btr.HasAttributeDefinitions )
  23.          {
  24.             foreach( ObjectId id in blockRef.AttributeCollection )
  25.             {
  26.                yield return (AttributeReference) tr.GetObject( id, OpenMode.ForRead );
  27.             }
  28.             foreach( ObjectId id in btr )
  29.             {
  30.                if( id.ObjectClass == attDefClass )
  31.                {
  32.                   AttributeDefinition attdef = (AttributeDefinition) tr.GetObject( id, OpenMode.ForRead );
  33.                   if( attdef.Constant )
  34.                      yield return attdef;
  35.                }
  36.             }
  37.          }
  38.       }
  39.  
  40.       // Requires an active transaction (not an OpenCloseTransaction)
  41.       // Returns a dictionary whose values are either constant AttributeDefinitions
  42.       // or AttributeReferences, keyed to their tags:
  43.  
  44.       public static Dictionary<string, DBText> GetAttributeDictionary( this BlockReference blockref )
  45.       {
  46.          return blockref.GetAttributes().ToDictionary( a => GetTag( a ), StringComparer.OrdinalIgnoreCase );
  47.       }
  48.  
  49.       public static Transaction GetTransaction( this DBObject obj )
  50.       {
  51.          if( obj.Database == null )
  52.             throw new ArgumentException( "No database" );
  53.          Transaction tr = obj.Database.TransactionManager.TopTransaction;
  54.          if( tr == null )
  55.             throw new InvalidOperationException( "No active transaction" );
  56.          return tr;
  57.       }
  58.  
  59.       static string GetTag( DBText dbtext )
  60.       {
  61.          AttributeDefinition attdef = dbtext as AttributeDefinition;
  62.          if( attdef != null )
  63.             return attdef.Tag;
  64.          AttributeReference attref = dbtext as AttributeReference;
  65.          if( attref != null )
  66.             return attref.Tag;
  67.          throw new ArgumentException( "requires an AttributeDefintion or AttributeReference" );
  68.       }
  69.    }
  70. }
  71.  
Title: Re: Easy way to get attributes from blocks
Post by: CADbloke on March 09, 2016, 06:01:41 PM
Like most things The Master left for us on this wonderful Internet thing we have, I have found this code useful. More than 1500 people have looked at this so I guess others find it useful too. I have broken tweaked it over the years so I thought I should share what I have come up with - it is basically the same as Tony's original with XML doc comments.

Code - C#: [Select]
  1. // Another Tony Tanzillo Classic
  2. // http://www.theswamp.org/index.php?topic=42591.msg477887#msg477887
  3.  
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using Autodesk.AutoCAD.Runtime;
  8. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  9. using AcRx = Autodesk.AutoCAD.Runtime;
  10.  
  11. namespace Autodesk.AutoCAD.DatabaseServices
  12. {
  13.     /// <summary> <c>Autodesk.AutoCAD.DatabaseServices</c> Extension methods mostly by Tony Tanzillo. </summary>
  14.     public static class AcDbExtensionMethods
  15.     {
  16.         private static readonly RXClass attDefClass = RXObject.GetClass(typeof (AttributeDefinition));
  17.  
  18.         /// <summary> Requires a transaction (not an OpenCloseTransaction) to be active when called:
  19.         ///     <para>Returns an enumeration of all <c>AttributeReference</c>s attached to the <c>BlockReference</c></para>
  20.         ///           plus all all <c>AttributeDefinition</c>s whose Constant property is true. </summary>
  21.         public static IEnumerable<DBText> GetAttributes(this BlockReference blockRef)
  22.         {
  23.             Transaction tr = blockRef.GetTransaction();
  24.             var btr = (BlockTableRecord)blockRef.DynamicBlockTableRecord.GetObject(OpenMode.ForRead);
  25.             if (btr.HasAttributeDefinitions)
  26.             {
  27.                 foreach (ObjectId id in blockRef.AttributeCollection)
  28.                 {
  29.                     yield return (AttributeReference)tr.GetObject(id, OpenMode.ForRead);
  30.                 }
  31.                 foreach (ObjectId id in btr)
  32.                 {
  33.                     if (id.ObjectClass == attDefClass)
  34.                     {
  35.                         var attdef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
  36.                         if (attdef.Constant)
  37.                             yield return attdef;
  38.                     }
  39.                 }
  40.             }
  41.         }
  42.  
  43.         // adapted from the above by CADbloke
  44.         /// <summary> Requires a transaction (not an OpenCloseTransaction) to be active when called:
  45.         ///     <para>Gets all the <c>AttributeReference</c>s from a <c>BlockReference</c></para>
  46.         ///           Does not get any Constant Attributes.</summary>
  47.         /// <param name="blockRef"> The BlockReference to get Attributes from. </param>
  48.         /// <returns> An enumerator that allows foreach to be used to process the attribute references in this collection. </returns>
  49.         public static IEnumerable<AttributeReference> GetAttributeReferences(this BlockReference blockRef)
  50.         {
  51.             Transaction tr = blockRef.GetTransaction();
  52.             var btr = (BlockTableRecord)blockRef.DynamicBlockTableRecord.GetObject(OpenMode.ForRead); // Dynamic?
  53.             if (btr.HasAttributeDefinitions)
  54.             {
  55.                 foreach (ObjectId id in blockRef.AttributeCollection)
  56.                 {
  57.                     yield return (AttributeReference)tr.GetObject(id, OpenMode.ForRead);
  58.                 }
  59.             }
  60.         }
  61.  
  62.         // adapted from the above by CADbloke
  63.         /// <summary> Requires a transaction (not an OpenCloseTransaction) to be active when called:
  64.         ///     <para>Gets all the <c>Constant</c> Attributes (<c>AttributeDefinition</c>s that are Constants) from a Block Reference. </para>
  65.         ///           Does not get any <c>AttributeReference</c>s.</summary>
  66.         public static IEnumerable<AttributeDefinition> GetAttributeConstants(this BlockReference blockRef)
  67.         {
  68.             Transaction tr = blockRef.GetTransaction();
  69.             var btr = (BlockTableRecord)blockRef.DynamicBlockTableRecord.GetObject(OpenMode.ForRead); //  Dynamic?
  70.             if (btr.HasAttributeDefinitions)
  71.             {
  72.                 foreach (ObjectId id in btr)
  73.                 {
  74.                     if (id.ObjectClass == attDefClass)
  75.                     {
  76.                         var attdef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
  77.                         if (attdef.Constant)
  78.                             yield return attdef;
  79.                     }
  80.                 }
  81.             }
  82.         }
  83.  
  84.         // adapted from the above by CADbloke
  85.         /// <summary> Requires a transaction (not an OpenCloseTransaction) to be active when called:
  86.         ///     <para>Gets all of the <c>AttributeDefinition</c>s from a <c>BlockReference</c>.</para> </summary>
  87.         public static IEnumerable<AttributeDefinition> GetAttributeDefinitions(this BlockReference blockRef)
  88.         {
  89.             Transaction tr = blockRef.GetTransaction();
  90.             var btr = (BlockTableRecord)blockRef.DynamicBlockTableRecord.GetObject(OpenMode.ForRead);
  91.             if (btr.HasAttributeDefinitions)
  92.             {
  93.                 foreach (ObjectId id in btr)
  94.                 {
  95.                     if (id.ObjectClass == attDefClass)
  96.                     {
  97.                         var attdef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
  98.                         /*if (attdef.Constant)*/
  99.                         {
  100.                             yield return attdef;
  101.                         }
  102.                     }
  103.                 }
  104.             }
  105.         }
  106.  
  107.         /// <summary> Requires an active transaction (not an OpenCloseTransaction).
  108.         ///     <para />Returns a dictionary whose values are either constant <c>AttributeDefinition</c>s
  109.         ///     or <c>AttributeReference</c>s, keyed to their tags: </summary>
  110.         public static Dictionary<string, DBText> GetAttributesToDictionaryKeyByTag(this BlockReference blockref)
  111.         {
  112.             return blockref.GetAttributes().ToDictionary(a => GetTag(a), StringComparer.OrdinalIgnoreCase);
  113.         }
  114.  
  115.  
  116.  
  117.         /// <summary> Gets the <c>Database.TransactionManager.TopTransaction</c>. </summary>
  118.         /// <exception cref="ArgumentNullException"> No database </exception>
  119.         /// <exception cref="Autodesk.AutoCAD.Runtime.Exception"> Requires an active transaction (NOT an OpenCloseTransaction) </exception>
  120.         public static Transaction GetTransaction(this DBObject obj)
  121.         {
  122.             if (obj.Database == null)
  123.                 throw new ArgumentNullException("obj", "No Database");
  124.  
  125.             Transaction tr = obj.Database.TransactionManager.TopTransaction;
  126.             if (tr == null)
  127.                 throw new AcRx.Exception(AcRx.ErrorStatus.NoActiveTransactions);
  128.  
  129.             return tr;
  130.         }
  131.  
  132.         /// <summary> Gets the tag of an <c>AttributeDefinition</c> or <c>AttributeReference</c>. </summary>
  133.         /// <exception cref="ArgumentException"> requires an AttributeDefintion or AttributeReference. </exception>
  134.         /// <param name="dbtext"> <c>AttributeDefinition</c> or <c>AttributeReference</c> ONLY. </param>
  135.         /// <returns> The tag. </returns>
  136.         private static string GetTag(DBText dbtext)
  137.         {
  138.             var attdef = dbtext as AttributeDefinition;
  139.             if (attdef != null)
  140.                 return attdef.Tag;
  141.             var attref = dbtext as AttributeReference;
  142.             if (attref != null)
  143.                 return attref.Tag;
  144.             throw new ArgumentException("requires an AttributeDefintion or AttributeReference");
  145.         }
  146.     }
  147. }