Author Topic: .NET BLOCK Routines  (Read 43506 times)

0 Members and 1 Guest are viewing this topic.

Galway

  • Guest
Re: .NET BLOCK Routines
« Reply #30 on: November 24, 2014, 07:55:36 PM »
Hi,

This is a simple and 'brute force' method to mimic the ATTSYNC command. It replaces the existing AttributeReferences from the inserted BlockReferences with new ones from the BlockTableRecord AttributeDefinitions.

The SynchronizeAttributes() method is defined as an extension method for the BlockTableRecord type so that it can be called as an instance method of this type.
Using example (assuming btr is a BlocTableRecord instance) : btr.SynchronizeAttributes()

<EDIT: corrected an issue w/ attributes in dynamic blocks>
<EDIT: corrected an issue w/ constant attributes>

 C# code
Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.Runtime;
  5. using AcRx = Autodesk.AutoCAD.Runtime;
  6.  
  7. namespace Autodesk.AutoCAD.DatabaseServices
  8. {
  9.     public static class ExtensionMethods
  10.     {
  11.         static RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
  12.  
  13.         public static void SynchronizeAttributes(this BlockTableRecord target)
  14.         {
  15.             if (target == null)
  16.                 throw new ArgumentNullException("target");
  17.  
  18.             Transaction tr = target.Database.TransactionManager.TopTransaction;
  19.             if (tr == null)
  20.                 throw new AcRx.Exception(ErrorStatus.NoActiveTransactions);
  21.             List<AttributeDefinition> attDefs = target.GetAttributes(tr);
  22.             foreach (ObjectId id in target.GetBlockReferenceIds(true, false))
  23.             {
  24.                 BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
  25.                 br.ResetAttributes(attDefs, tr);
  26.             }
  27.             if (target.IsDynamicBlock)
  28.             {
  29.                 target.UpdateAnonymousBlocks();
  30.                 foreach (ObjectId id in target.GetAnonymousBlockIds())
  31.                 {
  32.                     BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
  33.                     attDefs = btr.GetAttributes(tr);
  34.                     foreach (ObjectId brId in btr.GetBlockReferenceIds(true, false))
  35.                     {
  36.                         BlockReference br = (BlockReference)tr.GetObject(brId, OpenMode.ForWrite);
  37.                         br.ResetAttributes(attDefs, tr);
  38.                     }
  39.                 }
  40.             }
  41.         }
  42.  
  43.         private static List<AttributeDefinition> GetAttributes(this BlockTableRecord target, Transaction tr)
  44.         {
  45.             List<AttributeDefinition> attDefs = new List<AttributeDefinition>();
  46.             foreach (ObjectId id in target)
  47.             {
  48.                 if (id.ObjectClass == attDefClass)
  49.                 {
  50.                     AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
  51.                     attDefs.Add(attDef);
  52.                 }
  53.             }
  54.             return attDefs;
  55.         }
  56.  
  57.         private static void ResetAttributes(this BlockReference br, List<AttributeDefinition> attDefs, Transaction tr)
  58.         {
  59.             Dictionary<string, string> attValues = new Dictionary<string, string>();
  60.             foreach (ObjectId id in br.AttributeCollection)
  61.             {
  62.                 if (!id.IsErased)
  63.                 {
  64.                     AttributeReference attRef = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
  65.                     attValues.Add(attRef.Tag,
  66.                         attRef.IsMTextAttribute ? attRef.MTextAttribute.Contents : attRef.TextString);
  67.                     attRef.Erase();
  68.                 }
  69.             }
  70.             foreach (AttributeDefinition attDef in attDefs)
  71.             {
  72.                 AttributeReference attRef = new AttributeReference();
  73.                 attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
  74.                 if (attDef.Constant)
  75.                 {
  76.                     attRef.TextString = attDef.IsMTextAttributeDefinition ?
  77.                         attDef.MTextAttributeDefinition.Contents :
  78.                         attDef.TextString;
  79.                 }
  80.                 else if (attValues.ContainsKey(attRef.Tag))
  81.                 {
  82.                     attRef.TextString = attValues[attRef.Tag];
  83.                 }
  84.                 br.AttributeCollection.AppendAttribute(attRef);
  85.                 tr.AddNewlyCreatedDBObject(attRef, true);
  86.             }
  87.         }
  88.     }
  89. }

VB code (have to clear the Root Namespace in the project to add these extension methods to Autodesk.AutoCAD.DatabaseServices)
Code - vb.net: [Select]
  1. Imports Autodesk.AutoCAD.DatabaseServices
  2. Imports Autodesk.AutoCAD.Runtime
  3.  
  4. Namespace Autodesk.AutoCAD.DatabaseServices
  5.     Public Module ExtensionMethods
  6.  
  7.         Dim attDefClass As RXClass = RXClass.GetClass(GetType(AttributeDefinition))
  8.  
  9.         <System.Runtime.CompilerServices.Extension> _
  10.         Public Sub SynchronizeAttributes(target As BlockTableRecord)
  11.             If target Is Nothing Then
  12.                 Throw New ArgumentNullException("target")
  13.             End If
  14.  
  15.             Dim tr As Transaction = target.Database.TransactionManager.TopTransaction
  16.             If tr Is Nothing Then
  17.                 Throw New Exception(ErrorStatus.NoActiveTransactions)
  18.             End If
  19.  
  20.             Dim attDefs As List(Of AttributeDefinition) = target.GetAttributes(tr)
  21.             For Each id As ObjectId In target.GetBlockReferenceIds(True, False)
  22.                 Dim br As BlockReference = _
  23.                     DirectCast(tr.GetObject(id, OpenMode.ForWrite), BlockReference)
  24.                 br.ResetAttributes(attDefs, tr)
  25.             Next
  26.             If target.IsDynamicBlock Then
  27.                 target.UpdateAnonymousBlocks()
  28.                 For Each id As ObjectId In target.GetAnonymousBlockIds()
  29.                     Dim btr As BlockTableRecord = _
  30.                         DirectCast(tr.GetObject(id, OpenMode.ForRead), BlockTableRecord)
  31.                     attDefs = btr.GetAttributes(tr)
  32.                     For Each brId As ObjectId In btr.GetBlockReferenceIds(True, False)
  33.                         Dim br As BlockReference = _
  34.                             DirectCast(tr.GetObject(brId, OpenMode.ForWrite), BlockReference)
  35.                         br.ResetAttributes(attDefs, tr)
  36.                     Next
  37.                 Next
  38.             End If
  39.         End Sub
  40.  
  41.         <System.Runtime.CompilerServices.Extension> _
  42.         Private Function GetAttributes(target As BlockTableRecord, tr As Transaction) As List(Of AttributeDefinition)
  43.             Dim attdefs As List(Of AttributeDefinition) = New List(Of AttributeDefinition)
  44.             For Each id As ObjectId In target
  45.                 If id.ObjectClass = attDefClass Then
  46.                     Dim attDef As AttributeDefinition = _
  47.                         DirectCast(tr.GetObject(id, OpenMode.ForRead), AttributeDefinition)
  48.                     attdefs.Add(attDef)
  49.                 End If
  50.             Next
  51.             Return attdefs
  52.         End Function
  53.  
  54.         <System.Runtime.CompilerServices.Extension> _
  55.         Private Sub ResetAttributes(br As BlockReference, attDefs As List(Of AttributeDefinition), tr As Transaction)
  56.             Dim attValues As New Dictionary(Of String, String)()
  57.             For Each id As ObjectId In br.AttributeCollection
  58.                 If Not id.IsErased Then
  59.                     Dim attRef As AttributeReference = _
  60.                         DirectCast(tr.GetObject(id, OpenMode.ForWrite), AttributeReference)
  61.                     attValues.Add( _
  62.                         attRef.Tag, _
  63.                         If(attRef.IsMTextAttribute, attRef.MTextAttribute.Contents, attRef.TextString))
  64.                     attRef.Erase()
  65.                 End If
  66.             Next
  67.             For Each attDef As AttributeDefinition In attDefs
  68.                 Dim attRef As New AttributeReference()
  69.                 attRef.SetAttributeFromBlock(attDef, br.BlockTransform)
  70.                 If attDef.Constant Then
  71.                     attRef.TextString = If(attDef.IsMTextAttributeDefinition, _
  72.                                            attDef.MTextAttributeDefinition.Contents, _
  73.                                            attDef.TextString)
  74.                 Else If attValues IsNot Nothing AndAlso attValues.ContainsKey(attDef.Tag) Then
  75.                     attRef.TextString = attValues(attDef.Tag.ToUpper())
  76.                 End If
  77.                 br.AttributeCollection.AppendAttribute(attRef)
  78.                 tr.AddNewlyCreatedDBObject(attRef, True)
  79.             Next
  80.         End Sub
  81.  
  82.     End Module
  83.  
  84. End Namespace

This is fantastic gile. One thing though, is there any way to keep the "Prompt" field of the attribute definitions? I've slightly modified this to act as an attribute definition copy tool (to let me select a source block and copy its attribute definitions to another block). The attribute definitions seemingly keep most of their properties when transferred over, but the "Prompt" fields show up blank. Poking around in ObjectArx and the debugger, I don't see any obvious way to do this, but maybe there's something I'm missing.