.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

All blocks by name

11 REPLIES 11
SOLVED
Reply
Message 1 of 12
Rob.O
1954 Views, 11 Replies

All blocks by name

Hi All,

 

I know I am missing something very simple here (and i am sure I have done this before, but cannot find the code), but I basically need to get all blocks (dynamic in this case) with a particular name.

 

I can do it easily by searching through all blocks in the drawing, but it's a bit slow:

 

Dim acDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
'Declare document lock
Dim acDocLock As DocumentLock = acDoc.LockDocument
Dim acCurDb As Database = acDoc.Database

        'Start a transaction to open the recently copied title-block file and edit the attributes
        Using acTrans As Transaction = acDoc.TransactionManager.StartTransaction
            Try

                'Get the blocktable from the current open drawing
                Dim acBT As BlockTable = acCurDb.BlockTableId.GetObject(OpenMode.ForRead)
                
                'Iterrate through block table to determine if they are layouts or not
                For Each btrObjId As ObjectId In acBT

                    Dim btr As BlockTableRecord = btrObjId.GetObject(OpenMode.ForRead)

                    If btr.IsLayout Then
                        Continue For
                    End If

                    Dim objIdColl As ObjectIdCollection = btr.GetBlockReferenceIds(True, True)

                    For Each objId In objIdColl

                        Dim acBref As BlockReference = objId.GetObject(OpenMode.ForWrite)
                        Dim myAttValsTB As New Dictionary(Of String, String)

                        If acBref.Name = "ECDT_IssueStatus" Then
                           
			'Do stuff to attributes here...

                        End If

                        If acBref.IsDynamicBlock = True Then
                            Dim acBlkDef As BlockTableRecord = acBref.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)
                            Dim acDynObjId As ObjectId = acBref.DynamicBlockTableRecord
                            Dim dynBtr As BlockTableRecord = CType(acTrans.GetObject(acDynObjId, OpenMode.ForRead, False), BlockTableRecord)
                            If dynBtr.Name = "ECDT_IssueStatus" Then

		  	    'Do stuff to dynamic properties here...

                                Dim strDynParameterName As String = "Visibility1"
                                Dim strDynValue As String = strSubState
                                Dim acDynBref As BlockReference = objId.GetObject(OpenMode.ForRead)
                                For Each myDynamProp As DynamicBlockReferenceProperty In _
                                    acDynBref.DynamicBlockReferencePropertyCollection()
                                    If myDynamProp.PropertyName.Equals( _
                                        strDynParameterName, StringComparison.OrdinalIgnoreCase) = True Then
                                        myDynamProp.Value = strDynValue
                                    End If
                                Next
                            End If
                        End If

                    Next
                Next
Finally
            End Try
	actrans.commit()
acDocLock.Dispose()

        End Using

 

 Again, the above works with no problems other than being slow.

 

So I figured since I already know the block name, I can just use it to get all of the blocks in the drawing.  But for some reason, with the code below, the collection (btrids) is never populated.  What am I doing wrong?

 

Dim Blockname As String = "ECDT_IssueStatus"
Dim acDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
'Declare document lock
Dim acDocLock As DocumentLock = acDoc.LockDocument
Dim acCurDb As Database = acDoc.Database

        Using acTrans As Transaction = acDoc.TransactionManager.StartTransaction
            Try

                Dim BT As BlockTable = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
               
                If BT.Has(Blockname) Then
                    Dim btr As BlockTableRecord = acTrans.GetObject(bt(Blockname), OpenMode.ForRead)
                    
                    Dim btrIDs As ObjectIdCollection = btr.GetBlockReferenceIds(True, False)
                  
                    For Each id As ObjectId In btrIDs
                        If Not id.IsEffectivelyErased Then

                            Dim acBref As BlockReference = id.GetObject(OpenMode.ForWrite)
                            
				'Do stuff to block attributes here...
                            
                            If acBref.IsDynamicBlock = True Then
                                Dim acBlkDef As BlockTableRecord = acBref.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)
                                Dim acDynObjId As ObjectId = acBref.DynamicBlockTableRecord
                                Dim dynBtr As BlockTableRecord = CType(acTrans.GetObject(acDynObjId, OpenMode.ForRead, False), BlockTableRecord)
                                If dynBtr.Name = "ECDT_IssueStatus" Then

                                   'Do stuff to dynamic properties here...

                                End If
                            End If

                        End If
                    Next
                End If

                acTrans.Commit()
                acDocLock.Dispose()

           Finally
            End Try
        End Using

 

 

11 REPLIES 11
Message 2 of 12
Rob.O
in reply to: Rob.O

OK... tested this with a normal block, so it has something to do with the fact that it is a dynamic block.  So how can I get all of the dynamic block references in the drawing using the blockname?

 

Message 3 of 12
jeff
in reply to: Rob.O

When you insert a dynamic block and change a dynamic propertty then a anonymous block is created.

 

BlockTableRecord.GetBlockReferenceIds should only contain the blockreferences that have not had any changes to dynamic properties(default state)

 

 

You can use BlockTableRecord.GetAnonymousBlockIds to get anonymous block ids.

 

Also you can use BlockTableRecord.IsDynamicBlock Property to check at the definition level.

 

Here is a little code to help explain

 

<CommandMethod("ChangeVisState")> _
        Public Sub ChangeVisState()
            Dim Blockname As String = "C"

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor


            Using trx As Transaction = db.TransactionManager.StartTransaction


                Dim bt As BlockTable = trx.GetObject(db.BlockTableId, OpenMode.ForRead)

                If bt.Has(Blockname) Then

                    Dim btr As BlockTableRecord = trx.GetObject(bt(Blockname), OpenMode.ForRead)

                    Dim btrIDs As ObjectIdCollection = btr.GetBlockReferenceIds(True, False)

                    If btr.IsDynamicBlock Then

                        For Each id As ObjectId In btr.GetAnonymousBlockIds
                            Dim anonBlock As BlockTableRecord = trx.GetObject(id, OpenMode.ForRead)
                            For Each anonId As ObjectId In anonBlock.GetBlockReferenceIds(True, False)
                                btrIDs.Add(anonId)
                            Next
                        Next

                    End If

                    For Each id As ObjectId In btrIDs
                        If Not id.IsEffectivelyErased Then

                            Dim bref As BlockReference = id.GetObject(OpenMode.ForWrite)

                            For Each dynProp As DynamicBlockReferenceProperty In bref.DynamicBlockReferencePropertyCollection
                                If dynProp.PropertyName = "Visibility1" Then
                                    dynProp.Value = "VisibilityState3"
                                End If
                            Next

                        End If
                    Next
                End If

                trx.Commit()


            End Using
        End Sub

 

You can also find your answers @ TheSwamp
Message 4 of 12
mohnston
in reply to: Rob.O

This is C# but might help.

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

 

CAD Programming Solutions
Message 5 of 12
Rob.O
in reply to: mohnston

Excellent!  Works great and good reading!!!

 

I have been able to work with dynamic blocks in the past with no isses, but only after processing them with a user pick. Never tried to do it by itterating the block table so I was not sure how to do it (with a name).

 

Taking this a step further... how can I filter this down to only pulling the dynamic blocks (by a certain name) from the current layout?

 

I use the following for a standard block reference and then filter for the name later, but not sure how in this case:

 

acBtr = acCurDb.CurrentSpaceId.GetObject(OpenMode.ForRead)

 How do I filter that with a dynamic block name?

Message 6 of 12
jeff
in reply to: Rob.O

You could itterate the space and make sure it's BlockReference.DynamicBlockTableRecord property match or checking a blockreference's BlockId to see if it matches Database.CurrentSpaceId

You can also find your answers @ TheSwamp
Message 7 of 12
Rob.O
in reply to: jeff

Got it!  Thanks for the tip!

Message 8 of 12
Rob.O
in reply to: Rob.O

Now that I have all of the blocks in the drawing by particular name, I need to keep only those that are currently inserted in ModelSpace. 

 

Can someone kindly give me some advice on doing this?  I am struggling with it a bit!

 

TIA

Message 9 of 12
Rob.O
in reply to: Rob.O

A little more information... I thought this was working correctly for the last couple of months until I discovered this issue!!! Smiley Embarassed

 

The problem I am running into is that the code reads the entire database.  It even searches within other blocks!  So for example, if I code to get all blocks with the name of "ABLOCK" it searches the entire database and adds every instance of that block to my collection. The real problem is that it will search for instances of "ABLOCK" nested in a block that has a block table record, but is not inserted in the drawing.

 

So in other words, if I create a new block called "BBLOCK" that contains a nested "ABLOCK", then I delete the "BBLOCK" but do not purge the drawing, the code will still count the "ABLOCK".  I have coded for .IsErased and IsEffectivelyErased, but I think this is something different.

 

So... how can I get all blocks named "ABLOCK" by name that are BlockReferences (Inserts) in ModelSpace only?  And, not as important, but how do I stop it from searching for nested blocks?

 

The code I am using is below:

 

Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction

                Try
                Dim acBt As BlockTable = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
                
                If acBt.Has(blkName) Then

                    Dim acBtr As BlockTableRecord = acTrans.GetObject(acBt(blkName), OpenMode.ForRead)
                    Dim objIdColl As ObjectIdCollection = acBtr.GetBlockReferenceIds(True, False)

                    If acBtr.IsDynamicBlock Then
                        For Each id As ObjectId In acBtr.GetAnonymousBlockIds
                            If Not id.IsEffectivelyErased Then
                                If Not id.IsErased Then
                                    Dim anonBlock As BlockTableRecord = acTrans.GetObject(id, OpenMode.ForRead)
                                    For Each anonId As ObjectId In anonBlock.GetBlockReferenceIds(True, False)
                                        objIdColl.Add(anonId)
                                    Next
                                End If
                            End If
                        Next
                    End If

                    For Each objId As ObjectId In objIdColl
                        Dim acEnt As Entity = objId.GetObject(OpenMode.ForRead) 'added
                        If Not objId.IsEffectivelyErased Then
                            If Not objId.IsErased Then

                                Dim acBref As BlockReference = objId.GetObject(OpenMode.ForRead)

'<Snip>

 

Maybe I should start a new thread on this "sub" topic as this thread is a couple of months old?

 

 

Message 10 of 12
jeff
in reply to: Rob.O

Have not tested, but

 

For both cases of counting inserts with the block nested or not.

To not count the instance's inserted in other definitions you could check if the blockreference's OwnerId or BlockId is equal to ModelSpace's ObjectId

 

So to get the refereneces in model space that are nested set the first argument of GetBlockReferenceIds to false or true if not wanting the nested references, but for both cases excluded the blockreference's where OwnerId or BlockId do not match a modelspace or any of the spaces Objectid

You can also find your answers @ TheSwamp
Message 11 of 12
jeff
in reply to: jeff

Here is another example

http://www.theswamp.org/index.php?topic=40440.msg457662#msg457662

You can also find your answers @ TheSwamp
Message 12 of 12
Rob.O
in reply to: jeff

Ahhh... thanks so much Jeff!

 

It took me a bit to wrap my head around that, but I think I got it.  With some help from the thread you linked, I was able to come up with a filter to remove the block definitions that did not have *Model_Space as their owner.

 

Someday I will get this stuff figured out! 🙂

 

Thanks again!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost