Hi,
This is a simple and 'brute force' method to mimic the ATTSYNC command. It erases the existing AttributeReferences from the inserted BlockReferences and adds them 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: works now w/ mtext attributes>
<EDIT: corrected an issue w/ attributes in dynamic blocks>
<EDIT: corrected an issue w/ constant attributes>
C# code
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using AcRx = Autodesk.AutoCAD.Runtime;
namespace Autodesk.AutoCAD.DatabaseServices
{
public static class ExtensionMethods
{
static RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
public static void SynchronizeAttributes(this BlockTableRecord target)
{
if (target == null)
throw new ArgumentNullException("target");
Transaction tr = target.Database.TransactionManager.TopTransaction;
if (tr == null)
throw new AcRx.Exception(ErrorStatus.NoActiveTransactions);
List<AttributeDefinition> attDefs = target.GetAttributes(tr);
foreach (ObjectId id in target.GetBlockReferenceIds(true, false))
{
BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
br.ResetAttributes(attDefs, tr);
}
if (target.IsDynamicBlock)
{
target.UpdateAnonymousBlocks();
foreach (ObjectId id in target.GetAnonymousBlockIds())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
attDefs = btr.GetAttributes(tr);
foreach (ObjectId brId in btr.GetBlockReferenceIds(true, false))
{
BlockReference br = (BlockReference)tr.GetObject(brId, OpenMode.ForWrite);
br.ResetAttributes(attDefs, tr);
}
}
}
}
private static List<AttributeDefinition> GetAttributes(this BlockTableRecord target, Transaction tr)
{
List<AttributeDefinition> attDefs = new List<AttributeDefinition>();
foreach (ObjectId id in target)
{
if (id.ObjectClass == attDefClass)
{
AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
attDefs.Add(attDef);
}
}
return attDefs;
}
private static void ResetAttributes(this BlockReference br, List<AttributeDefinition> attDefs, Transaction tr)
{
Dictionary<string, string> attValues = new Dictionary<string, string>();
foreach (ObjectId id in br.AttributeCollection)
{
if (!id.IsErased)
{
AttributeReference attRef = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
attValues.Add(attRef.Tag,
attRef.IsMTextAttribute ? attRef.MTextAttribute.Contents : attRef.TextString);
attRef.Erase();
}
}
foreach (AttributeDefinition attDef in attDefs)
{
AttributeReference attRef = new AttributeReference();
attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
if (attDef.Constant)
{
attRef.TextString = attDef.IsMTextAttributeDefinition ?
attDef.MTextAttributeDefinition.Contents :
attDef.TextString;
}
else if (attValues.ContainsKey(attRef.Tag))
{
attRef.TextString = attValues[attRef.Tag];
}
br.AttributeCollection.AppendAttribute(attRef);
tr.AddNewlyCreatedDBObject(attRef, true);
}
}
}
}
VB code (have to clear the Root Namespace in the project to add these extension methods to Autodesk.AutoCAD.DatabaseServices)
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Runtime
Namespace Autodesk.AutoCAD.DatabaseServices
Public Module ExtensionMethods
Dim attDefClass As RXClass = RXClass.GetClass(GetType(AttributeDefinition))
<System.Runtime.CompilerServices.Extension> _
Public Sub SynchronizeAttributes(target As BlockTableRecord)
If target Is Nothing Then
Throw New ArgumentNullException("target")
End If
Dim tr As Transaction = target.Database.TransactionManager.TopTransaction
If tr Is Nothing Then
Throw New Exception(ErrorStatus.NoActiveTransactions)
End If
Dim attDefs As List(Of AttributeDefinition) = target.GetAttributes(tr)
For Each id As ObjectId In target.GetBlockReferenceIds(True, False)
Dim br As BlockReference = _
DirectCast(tr.GetObject(id, OpenMode.ForWrite), BlockReference)
br.ResetAttributes(attDefs, tr)
Next
If target.IsDynamicBlock Then
target.UpdateAnonymousBlocks()
For Each id As ObjectId In target.GetAnonymousBlockIds()
Dim btr As BlockTableRecord = _
DirectCast(tr.GetObject(id, OpenMode.ForRead), BlockTableRecord)
attDefs = btr.GetAttributes(tr)
For Each brId As ObjectId In btr.GetBlockReferenceIds(True, False)
Dim br As BlockReference = _
DirectCast(tr.GetObject(brId, OpenMode.ForWrite), BlockReference)
br.ResetAttributes(attDefs, tr)
Next
Next
End If
End Sub
<System.Runtime.CompilerServices.Extension> _
Private Function GetAttributes(target As BlockTableRecord, tr As Transaction) As List(Of AttributeDefinition)
Dim attdefs As List(Of AttributeDefinition) = New List(Of AttributeDefinition)
For Each id As ObjectId In target
If id.ObjectClass = attDefClass Then
Dim attDef As AttributeDefinition = _
DirectCast(tr.GetObject(id, OpenMode.ForRead), AttributeDefinition)
attdefs.Add(attDef)
End If
Next
Return attdefs
End Function
<System.Runtime.CompilerServices.Extension> _
Private Sub ResetAttributes(br As BlockReference, attDefs As List(Of AttributeDefinition), tr As Transaction)
Dim attValues As New Dictionary(Of String, String)()
For Each id As ObjectId In br.AttributeCollection
If Not id.IsErased Then
Dim attRef As AttributeReference = _
DirectCast(tr.GetObject(id, OpenMode.ForWrite), AttributeReference)
attValues.Add( _
attRef.Tag, _
If(attRef.IsMTextAttribute, attRef.MTextAttribute.Contents, attRef.TextString))
attRef.Erase()
End If
Next
For Each attDef As AttributeDefinition In attDefs
Dim attRef As New AttributeReference()
attRef.SetAttributeFromBlock(attDef, br.BlockTransform)
If attDef.Constant Then
attRef.TextString = If(attDef.IsMTextAttributeDefinition, _
attDef.MTextAttributeDefinition.Contents, _
attDef.TextString)
Else If attValues IsNot Nothing AndAlso attValues.ContainsKey(attDef.Tag) Then
attRef.TextString = attValues(attDef.Tag.ToUpper())
End If
br.AttributeCollection.AppendAttribute(attRef)
tr.AddNewlyCreatedDBObject(attRef, True)
Next
End Sub
End Module
End Namespace