.NET

Reply
Valued Contributor
mindofcat
Posts: 55
Registered: ‎05-14-2012
Message 1 of 6 (652 Views)
Accepted Solution

ATTSYNC in VB.NET

652 Views, 5 Replies
11-22-2013 11:28 AM

Hi all,

 

Does anyone know what the dot net equivalent is for attsync?

 

I use invisible attributes in the block references created by my dot net code, but I just noticed a strange AutoCAD behaviour:

 

Right-clicking on the block with attributes, and selecting the 'Edit Block in-place' option correctly displays the hidden attributes, making it possible for them to be deleted.

 

However, after deleting all the attributes and saving the ref edit, I right-click on the same block again, this time to check if it still has attibutes; and it does, even though I deleted all the attributes! There seems to be some sort of 'held-in-memory' issue here, which, after I did some research, I discovered that the ATTSYNC command is perfect for purging those deleted attributes from the block reference, AFTER they have been physically deleted.

 

The problem is, how do I implement this ATTSYNC command in my dot net code, without using sendcommand? 

 

I found a thread on this forum regarding this issue, which led me to the swamp; but then the code I found there is in F#, and so I was wondering if anyone knows of a simple VB.NET way of mimicking the AutoCAD ATTSYNC command?

 

Many thanks...

 

Cat

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 2 of 6 (602 Views)

Re : ATTSYNC in VB.NET

11-23-2013 10:01 AM in reply to: mindofcat

Hi,

 

Here's a simple and 'brute force' method which 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.

 

Example (assuming btr is a BlocTableRecord instance) : btr.SynchronizeAttributes()

 

C# code

using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using AcRx = Autodesk.AutoCAD.Runtime;

namespace AttSyncSample
{
    public static class ExtensionMethods
    {
        public static void SynchronizeAttributes(this BlockTableRecord target)
        {
            if (target == null)
                throw new ArgumentNullException("btr");

            Transaction tr = target.Database.TransactionManager.TopTransaction;
            if (tr == null)
                throw new AcRx.Exception(ErrorStatus.NoActiveTransactions);


            RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
            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);
                }
            }
            foreach (ObjectId id in target.GetBlockReferenceIds(true, false))
            {
                BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
                br.ResetAttributes(attDefs);
            }
            if (target.IsDynamicBlock)
            {
                foreach (ObjectId id in target.GetAnonymousBlockIds())
                {
                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
                    foreach (ObjectId brId in btr.GetBlockReferenceIds(true, false))
                    {
                        BlockReference br = (BlockReference)tr.GetObject(brId, OpenMode.ForWrite);
                        br.ResetAttributes(attDefs);
                    }
                }
            }
        }

        private static void ResetAttributes(this BlockReference br, List<AttributeDefinition> attDefs)
        {
            TransactionManager tm = br.Database.TransactionManager;
            Dictionary<string, string> attValues = new Dictionary<string, string>();
            foreach (ObjectId id in br.AttributeCollection)
            {
                if (!id.IsErased)
                {
                    AttributeReference attRef = (AttributeReference)tm.GetObject(id, OpenMode.ForWrite);
                    attValues.Add(attRef.Tag, attRef.TextString);
                    attRef.Erase();
                }
            }
            foreach (AttributeDefinition attDef in attDefs)
            {
                AttributeReference attRef = new AttributeReference();
                attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
                if (attValues.ContainsKey(attDef.Tag))
                {
                    attRef.TextString = attValues[attDef.Tag.ToUpper()];
                }
                br.AttributeCollection.AppendAttribute(attRef);
                tm.AddNewlyCreatedDBObject(attRef, true);
            }
        }
    }
}

 

VB code

Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Runtime

Module ExtensionMethods

    <System.Runtime.CompilerServices.Extension> _
    Public Sub SynchronizeAttributes(target As BlockTableRecord)
        If target Is Nothing Then
            Throw New ArgumentNullException("btr")
        End If

        Dim tr As Transaction = target.Database.TransactionManager.TopTransaction
        If tr Is Nothing Then
            Throw New Exception(ErrorStatus.NoActiveTransactions)
        End If

        Dim attDefClass As RXClass = RXClass.GetClass(GetType(AttributeDefinition))
        Dim attDefs As 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
        For Each id As ObjectId In target.GetBlockReferenceIds(True, False)
            Dim br As BlockReference = DirectCast(tr.GetObject(id, OpenMode.ForWrite), BlockReference)
            br.ResetAttributes(attDefs)
        Next
        If target.IsDynamicBlock Then
            For Each id As ObjectId In target.GetAnonymousBlockIds()
                Dim btr As BlockTableRecord = DirectCast(tr.GetObject(id, OpenMode.ForRead), BlockTableRecord)
                For Each brId As ObjectId In btr.GetBlockReferenceIds(True, False)
                    Dim br As BlockReference = DirectCast(tr.GetObject(brId, OpenMode.ForWrite), BlockReference)
                    br.ResetAttributes(attDefs)
                Next
            Next
        End If
    End Sub

    <System.Runtime.CompilerServices.Extension> _
    Private Sub ResetAttributes(br As BlockReference, attDefs As List(Of AttributeDefinition))
        Dim tm As TransactionManager = br.Database.TransactionManager
        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(tm.GetObject(id, OpenMode.ForWrite), AttributeReference)
                attValues.Add(attRef.Tag, 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 attValues IsNot Nothing AndAlso attValues.ContainsKey(attDef.Tag) Then
                attRef.TextString = attValues(attDef.Tag.ToUpper())
            End If
            br.AttributeCollection.AppendAttribute(attRef)
            tm.AddNewlyCreatedDBObject(attRef, True)
        Next
    End Sub

End Module

 

Gilles Chanteau
Valued Contributor
mindofcat
Posts: 55
Registered: ‎05-14-2012
Message 3 of 6 (557 Views)

Re : ATTSYNC in VB.NET

11-25-2013 10:10 AM in reply to: _gile

Many thanks, Gilles... your code worked the magic!

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 4 of 6 (549 Views)

Re : ATTSYNC in VB.NET

11-25-2013 10:41 AM in reply to: mindofcat

You're welcome.

 

if you want it to work with mtext attributes, in the ResetAttributes method, replace:

 

attValues.Add(attRef.Tag, attRef.TextString)

with,

C#

attValues.Add(attRef.Tag,
    attRef.IsMTextAttribute ? attRef.MTextAttribute.Contents : attRef.TextString);

 

VB

attValues.Add( _
    attRef.Tag, _
    If(attRef.IsMTextAttribute, attRef.MTextAttribute.Contents, attRef.TextString))

 

Gilles Chanteau
*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 5 of 6 (516 Views)

Re : ATTSYNC in VB.NET

11-26-2013 06:07 AM in reply to: _gile

You can find a better implementation (works with multiline attributes, constant attributes, dynamic blocks) at TheSwamp:

http://www.theswamp.org/index.php?topic=31859.msg508802#msg508802

Gilles Chanteau
Valued Contributor
mindofcat
Posts: 55
Registered: ‎05-14-2012
Message 6 of 6 (503 Views)

Re : ATTSYNC in VB.NET

11-26-2013 07:31 AM in reply to: _gile
Quite right it is, worked like a charm! many thanks again!
Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.