I recently came across a pretty common problem where I needed to find all of the title block entities on each layout in the active drawing. The solution lies in the database layout dictionary as can be seen below. Special consideration needs to be taken if you're working with dynamic blocks. If you don't check if the block is dynamic, you're only getting the anonymous block, not the true dynamic block reference.
<CommandMethod("CollectTblocks")> _
Public Sub CollectTblocks()
' Get the current document database and active drawing
Dim oDb As Database = HostApplicationServices.WorkingDatabase
Dim oDwg As Autodesk.AutoCAD.ApplicationServices.Document = Application.DocumentManager.MdiActiveDocument
' Start a transaction
Dim oTrans As Transaction = oDb.TransactionManager.StartTransaction
' Get the current layout id and layout name
Dim curLayoutID As ObjectId = LayoutManager.Current.GetLayoutId(LayoutManager.Current.CurrentLayout)
Dim curLayout As Layout = CType(curLayoutID.GetObject(OpenMode.ForRead), Layout)
' Create an arraylist to store our layout entity ids in
Dim oTblocks As New ArrayList
Try
' Lock the drawing
Using locked As Autodesk.AutoCAD.ApplicationServices.DocumentLock = oDwg.LockDocument()
' Get the drawings layout dictionary
Dim layoutDict As DBDictionary = CType(oTrans.GetObject(oDb.LayoutDictionaryId, _
OpenMode.ForRead), DBDictionary)
Dim indexTb As Integer = 1
For Each id As DictionaryEntry In layoutDict
' Get the layout object
Dim oLayout As Layout = CType(oTrans.GetObject(CType(id.Value, ObjectId), _
OpenMode.ForRead), Layout)
Dim oBtr As BlockTableRecord = CType(oTrans.GetObject(oLayout.BlockTableRecordId, _
OpenMode.ForRead), BlockTableRecord)
If oBtr.IsLayout = True Then
' Get the enumerator
Dim oBtre As BlockTableRecordEnumerator = oBtr.GetEnumerator
' Loop through all blocks in the block table
While oBtre.MoveNext
Dim oEnt As Entity = CType(oTrans.GetObject(oBtre.Current, _
OpenMode.ForRead), Entity)
If TypeOf oEnt Is BlockReference Then
' Change the entity to a block reference
Dim oBr As BlockReference = CType(oEnt, BlockReference)
If oBr.IsDynamicBlock Then
' Get the object id of the dynamic block's parent
Dim oDoId As ObjectId = oBr.DynamicBlockTableRecord
' Get the block table record
Dim oDBtr As BlockTableRecord = CType(oTrans.GetObject(oDoId, _
OpenMode.ForRead), BlockTableRecord)
' Store the block reference id if the name matches
If oDBtr.Name.Equals("TITLEBLOCK") Then oTblocks.Add(oBtr.ObjectId)
Else
' Store the block reference id if the name matches
If oBr.Name.Equals("TITLEBLOCK") Then oTblocks.Add(oBtr.ObjectId)
End If
End If
End While
End If
Next
End Using
' Write a message stating how many title blocks were found
Dim oEd As Editor = oDwg.Editor
oEd.WriteMessage(oTblocks.Count.ToString & " title blocks were found in the drawing.")
' Close the transaction, aborting is faster than committing
oTrans.Abort()
Catch ex As System.Exception
MsgBox(ex.Message, MsgBoxStyle.Information, "Error in CollectTblocks")
Finally
' Clean up
oTrans.Dispose()
End Try
End Sub
So what does it do? In a nutshell, the routine above loops through each layout in the active drawing and looks for block references. If it finds a block reference it checks to see if the block is dynamic and then checks to see if the block name matches "TITLEBLOCK". If it finds a match, it stores the block reference object id in the array list.