Problem counting block references with GetBlockReferenceIds function

Problem counting block references with GetBlockReferenceIds function

Anonymous
Not applicable
1,466 Views
9 Replies
Message 1 of 10

Problem counting block references with GetBlockReferenceIds function

Anonymous
Not applicable

Hello everyone,

 

I am using the following code to erase all unused (not inserted) blocks from a drawing:

 

  Sub PurgeAll(ByVal myDB As Database)
' This procedure purge all the blocks that are not inserted in the drawing

Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
Dim myBT As BlockTable = myDB.BlockTableId.GetObject(OpenMode.ForRead)

For Each id As ObjectId In myBT

Dim myBTR As BlockTableRecord = CType(myTrans.GetObject(id, OpenMode.ForWrite), BlockTableRecord)

If myBTR.GetBlockReferenceIds(False, False).Count = 0 And Not myBTR.IsLayout Then
myBTR.Erase()
End If

Next
myTrans.Commit()
End Using
End Sub

 

Nevertheless, in some drawings the GetBlockReferenceIds.count function returns 1 for some blocks even though there are no instances inserted. I confirmed there are no blocks inserted erasing the blocks manually with the Purge command.

 

Why is this happening?

 

Thanks!

 

 

0 Likes
Accepted solutions (1)
1,467 Views
9 Replies
Replies (9)
Message 2 of 10

SENL1362
Advisor
Advisor
When you Purge manually do you purge Block Items only?
There may be other type of references to Blocks, such as a HardPointer link in ExtensionDirectoy coupled to an entity preventing the block to get purged.
Or the block might be used in (Line) Styles.

But the manual purge of only Blocks should then fail as well.
0 Likes
Message 3 of 10

Anonymous
Not applicable

I purged only Blocks, and they were removed...  I am not sure about these other references that you are talking about; I just want to remove those blocks that are not being used (are not inserted) in the drawing. Is there any other way to do this in .NET?

 

Thanks,

 

0 Likes
Message 4 of 10

_gile
Consultant
Consultant
Accepted solution

Hi,

 

You may have a look at the Database.Purge(ObjectIdCollection ids) method.

 

Extract from the docs:

This function searches through the databse to see if there are any hard references to objects with object ID entities in the ids array. If any such objects are found, their object ID entities are removed from the ids array. So, when this function returns, the ids array will contain only object ID entities of objects that are not currently hard-referenced and thus can safely be erased.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 5 of 10

Anonymous
Not applicable

Hi Gile,

 

I tried Database.purge in my drawing but the resulting ObjectIdCollection is empty...

 

However if I run the purge command manually all the unused blocks are listed (and can be removed). 

 

Do you have any idea what might be wrong?

 

Thanks,

0 Likes
Message 6 of 10

_gile
Consultant
Consultant

Try this snippet, it works fine for me.

The PurgeBlocks method is called in a While loop to ensure purging nested blocks (if any).

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Linq;

namespace PurgeBlockSample
{
    public class Commands
    {
        [CommandMethod("Test")]
        public void Test()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            int cnt;
            while ((cnt = PurgeBlocks(db)) > 0)
            {
                ed.WriteMessage("\nPurged: {0} block{1}", cnt, cnt > 1 ? "s" : "");
            }
        }

        private int PurgeBlocks(Database db)
        {
            ObjectIdCollection ids;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                ids = new ObjectIdCollection(bt.Cast<ObjectId>().ToArray());
                db.Purge(ids);
                foreach (ObjectId id in ids)
                {
                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForWrite);
                    btr.Erase();
                }
                tr.Commit();
            }
            return ids.Count;
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 7 of 10

_gile
Consultant
Consultant

VB code:

 

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime

Namespace PurgeBlockSample

    Public Class Commands

        <CommandMethod("Test")> _
        Public Sub Test()
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor
            While True
                Dim cnt = PurgeAllblocks(db)
                If cnt = 0 Then
                    Exit While
                End If
                ed.WriteMessage(vbLf + "Purged: {0} block{1}", cnt, IIf(cnt > 0, "s", ""))
            End While
        End Sub

        Function PurgeAllBlocks(ByVal db As Database) As Integer
            Dim cnt As Integer
            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim ids As ObjectIdCollection = New ObjectIdCollection()
                Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
                For Each id As ObjectId In bt
                    ids.Add(id)
                Next
                db.Purge(ids)
                cnt = ids.Count
                For Each id As ObjectId In ids
                    Dim btr As BlockTableRecord = _
                        DirectCast(tr.GetObject(id, OpenMode.ForWrite), BlockTableRecord)
                    btr.Erase()
                Next
                tr.Commit()
            End Using
            Return cnt
        End Function

    End Class

End Namespace

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 10

autodaug
Autodesk
Autodesk

This looks right. I wonder if the original attempt which failed was not correctly populating the ObjectIdCollection with all the BTR ids in the first place, before calling Purge().

 

About how these stray entries come to be in a BTR's reference list, there may be a few ways it can happen. I just now reproduced it by creating a drawing containing a nested block, and then erasing the one reference to the outer block. That left the inner block with a stray id in its reference list. Also, older versions of AutoCAD may not have been as diligent about updating the BTR reference list when a blockref entity was erased.

 

 

 

Message 9 of 10

autodaug
Autodesk
Autodesk

Actually, I think the original attempt probably failed because of not putting the Purge() call in a loop. That's needed in order to deal with nested blocks, as you mentioned.

 

In the nested block situation, one block B1 has a reference to another B2. So B2 is not initially purgeable. But if there are no references to B1, then we can purge B1 and now B2 becomes purgeable. That sounds like the situation here.

 

0 Likes
Message 10 of 10

Anonymous
Not applicable

Hello Giles,

 

I was confused about the use of the database.purge... your snippet helped me to understand it better. 

 

The code seems to be working now, thank you very much.

 

 

Best regards,

Daniel

0 Likes