ATTSYNC in VB.NET

ATTSYNC in VB.NET

Anonymous
Not applicable
12,920 Views
23 Replies
Message 1 of 24

ATTSYNC in VB.NET

Anonymous
Not applicable

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

0 Likes
Accepted solutions (2)
12,921 Views
23 Replies
Replies (23)
Message 21 of 24

CBennett34F8SS
Contributor
Contributor

This crosses many classes so I will try and show the relevant code.  This is where the attribute sync is called

 //Legacy titleblock was found
                if (oldTbList != null)
                {
                    using (Transaction acTrans = acDb.TransactionManager.StartTransaction())
                    {
                        BlockTable acBlkTbl = (BlockTable)acTrans.GetObject(acDb.BlockTableId, OpenMode.ForRead);
                        BlockTableRecord acBlkTblRec = (BlockTableRecord)acTrans.GetObject(acBlkTbl[oldTbList[0].Name], OpenMode.ForRead, false);

                        acBlkTblRec.SynchronizeAttributes();
                        acTrans.Commit();
                    }
                    _TbId = ReplaceTB(oldTbList, TbId, replaceLayout);
                }

I committed the transaction here.  If I don't commit then I get the old Attribute Collection later.  On line 100 in the below code is where I get eWasErased.

 

private ObjectId ReplaceTB(List<TitleBlkLegacyProps> oldTbList, ObjectId tbId, bool delLayout = false)
        {

            string[] blkName = { newTBName };

            //Import the new Title Block
            SysLog.WriteLineToLog(DateTime.Now.ToString("yyyy/MM/dd") + " " + DateTime.Now.ToString("hh:mm:ss tt - ") + "Importing replacement title block");
            AcDb.ImportMultiBlocks(blkName, TBFullPath);

            ObjectId blkRecId = ObjectId.Null;
            ObjectId acBlkRefInsertId = ObjectId.Null;

            using (Transaction acTrans = AcDb.TransactionManager.StartTransaction())
            {
                BlockTable acTblItm = (BlockTable)acTrans.GetObject(AcDb.BlockTableId, OpenMode.ForRead);

                //Get the Title block definition (BlockRecord)
                acBlkTblRec = (BlockTableRecord)acTrans.GetObject(acTblItm[newTBName], OpenMode.ForRead);
                blkRecId = acBlkTblRec.Id;

                //If the title block definition was found
                if (blkRecId != ObjectId.Null)
                {

                    using (BlockReference acBlkRefInsert = new BlockReference(new Point3d(0, 0, 0), blkRecId))
                    {
                        acBlkRefInsert.Layer = tbLayer;
                        BlockTableRecord acSpace;
                        if (delLayout == true)
                        {
                            //TODO get from DB
                            //Create New Layout, get the ID and block table record
                            AcLayout acLayout = new AcLayout("Add", "MRD-Print");
                            ObjectId acLayOID = acLayout.LayoutIdNew;
                            AcLayoutBtr = acLayout.LayoutBtrId;
                            //Get the Existing Paperspace Viewport
                            acLayout.GetVport(AcLayoutNameOld);
                            AcVprt = acLayout.ViewportOld;
                            //Create New viewport in New layout
                            new AcVprt(AcDb);
                            
                        }

                        acSpace = (BlockTableRecord)acTrans.GetObject(AcLayoutBtr.ObjectId, OpenMode.ForWrite);

                        acSpace.AppendEntity(acBlkRefInsert);
                        acTrans.AddNewlyCreatedDBObject(acBlkRefInsert, true);

                        acBlkRefInsertId = acBlkRefInsert.Id;

                        foreach (ObjectId id in acBlkTblRec)
                        {
                            DBObject obj = id.GetObject(OpenMode.ForRead);
                            AttributeDefinition attDef = obj as AttributeDefinition;
                            if ((attDef != null) && (!attDef.Constant))
                            {
                                using (AttributeReference attRef = new AttributeReference())
                                {
                                    attRef.SetAttributeFromBlock(attDef, acBlkRefInsert.BlockTransform);
                                    attRef.TextString = "";
                                    acBlkRefInsert.AttributeCollection.AppendAttribute(attRef);
                                    acTrans.AddNewlyCreatedDBObject(attRef, true);
                                }
                            }
                        }
                    }

                    BlockReference acBlkRefOld = (BlockReference)acTrans.GetObject(tbId, OpenMode.ForWrite);
                    BlockReference acBlkRefNew = (BlockReference)acTrans.GetObject(acBlkRefInsertId, OpenMode.ForWrite);
                    Dictionary<string, string> acBlkRefAttDict = acBlkRefOld.GetAttToDict(acBlkTblRec);
                    AttributeCollection acAttColOld = acBlkRefOld.AttributeCollection;
                    AttributeCollection acAttColNew = acBlkRefNew.AttributeCollection;

                    // TODO Get From DB create external clean up format RunScript???
                    string[] exclude = { "", " ", "  ", ".", "..", "...", "-", "_" };
                    string replaceChar = ".";
                    string tbSaveAsTag = "DWGNO";

                    for (int i = 0; i <= oldTbList.Count - 1; i++)
                    {
                        string[] attValue = new string[1];
                        string[] attTag = new string[1];
                        string[] attCombine = new string[1];
                        if (oldTbList[i].AttOldIndex.Contains(";"))
                        {
                            attValue = oldTbList[i].AttOldIndex.Split(';');
                            attTag = oldTbList[i].AttOldTag.Split(';');
                            attCombine = oldTbList[i].CombineChar.Split(';');
                        }
                        else
                        {
                            attValue[0] = oldTbList[i].AttOldIndex;
                            attTag[0] = oldTbList[i].AttOldTag;
                            attCombine[0] = oldTbList[i].CombineChar;
                        }

                        for (int j = 0; j <= attValue.Length - 1; j++)
                        {
                            int attOld = Convert.ToInt32(attValue[j]);
                            AttributeReference attRefOld = (AttributeReference)acTrans.GetObject(acAttColOld[attOld], OpenMode.ForWrite);
                            if (attRefOld.Tag.Equals(attTag[j], StringComparison.OrdinalIgnoreCase))
                            {
                                int attNew = Convert.ToInt32(oldTbList[i].AttNewIndex);
                                AttributeReference attRefNew = (AttributeReference)acTrans.GetObject(acAttColNew[attNew], OpenMode.ForWrite);

                                foreach (string excludeStr in exclude)
                                {
                                    if (attRefOld.TextString.Equals(excludeStr, StringComparison.OrdinalIgnoreCase))
                                    {
                                        attRefOld.TextString = "";
                                    }
                                }
                                attRefNew.TextString = attRefNew.TextString + attCombine[j] + attRefOld.TextString;
                            }
                        }
                    }
                    acBlkRefOld.Erase();

                    new AcLayout("DeleteContains", acLayNameOld: "Layer");
                    if (delLayout == true)
                    {
                        new AcLayout("Delete", acLayNameOld: AcLayoutNameOld);
                    }
                    

                    foreach (ObjectId attId in acAttColNew)
                    {

                        AttributeReference attRef = (AttributeReference)acTrans.GetObject(attId, OpenMode.ForWrite);

                        foreach (string excludeStr in exclude)
                        {
                            if (attRef.TextString.Equals(excludeStr, StringComparison.OrdinalIgnoreCase))
                            {
                                attRef.TextString = replaceChar;
                            }
                        }
                        if (attRef.Tag.Equals(tbSaveAsTag, StringComparison.OrdinalIgnoreCase))
                        {
                            FnClnUp fnClnUp = new FnClnUp(attRef.TextString);
                            attRef.TextString = fnClnUp.Filename;

                        }
                    }
                }
                else
                {
                    // TODO if the block wasnt found

                }

                acTrans.Commit();
            }

            tbId = acBlkRefInsertId;
            return acBlkRefInsertId;
        }

 

 

 

0 Likes
Message 22 of 24

_gile
Consultant
Consultant

It's quite difficult for me to read and understand your code but it looks like you use the ObjectIds of the 'old' attribute references, those which existed before you call the SynchronizeAttributes method. As explained in my first message, the  SynchronizeAttributes method "erases the existing AttributeReferences from the inserted BlockReferences and adds them new ones from the BlockTableRecord AttributeDefinitions". That means you need to re-open the attribute references from the new AttributeCollection.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 23 of 24

kgallagherCGHDN
Advocate
Advocate

i run this with no issue, however, what i am hoping to get is the attributes shifting back to the correct location. if i run Attsync it will fix the attribute locations. this code does not. did i miss something?

0 Likes
Message 24 of 24

brian.k.smith
Advocate
Advocate

I think that you need something like this:

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 Autodesk.AutoCAD.DatabaseServices.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
0 Likes