.NET

Reply
Mentor
Rob.O
Posts: 256
Registered: ‎06-25-2007
Message 1 of 12 (603 Views)
Accepted Solution

All blocks by name

603 Views, 11 Replies
11-17-2011 02:47 PM

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

 

 

Mentor
Rob.O
Posts: 256
Registered: ‎06-25-2007
Message 2 of 12 (595 Views)

Re: All blocks by name

11-17-2011 03:37 PM 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?

 

Valued Mentor
Posts: 319
Registered: ‎05-12-2009
Message 3 of 12 (590 Views)

Re: All blocks by name

11-17-2011 03:46 PM 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
Distinguished Contributor
Posts: 184
Registered: ‎09-22-2006
Message 4 of 12 (583 Views)

Re: All blocks by name

11-17-2011 04:04 PM in reply to: Rob.O

This is C# but might help.

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

 

CAD Programming Solutions
Mentor
Rob.O
Posts: 256
Registered: ‎06-25-2007
Message 5 of 12 (555 Views)

Re: All blocks by name

11-18-2011 08:51 AM 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?

Valued Mentor
Posts: 319
Registered: ‎05-12-2009
Message 6 of 12 (553 Views)

Re: All blocks by name

11-18-2011 09:05 AM 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
Mentor
Rob.O
Posts: 256
Registered: ‎06-25-2007
Message 7 of 12 (550 Views)

Re: All blocks by name

11-18-2011 09:21 AM in reply to: jeff

Got it!  Thanks for the tip!

Mentor
Rob.O
Posts: 256
Registered: ‎06-25-2007
Message 8 of 12 (470 Views)

Re: All blocks by name

01-17-2012 01:13 PM 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

Mentor
Rob.O
Posts: 256
Registered: ‎06-25-2007
Message 9 of 12 (457 Views)

Re: All blocks by name

01-17-2012 03:03 PM 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!!! :smileyembarrassed:

 

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?

 

 

Valued Mentor
Posts: 319
Registered: ‎05-12-2009
Message 10 of 12 (450 Views)

Re: All blocks by name

01-17-2012 06:05 PM 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

You are not logged in.

Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register

Announcements
Welcome to the new Autodesk Community!
If this is your first visit, click here to get started and make the most of the Community. Let us know what you think of the new experience in the Community Feedback Forum.

Need installation help?

Start with some of our most frequented solutions to get help installing your software.

Ask the Community