.NET

Reply
Contributor
kbrown
Posts: 21
Registered: ‎10-23-2012
Message 1 of 5 (561 Views)
Accepted Solution

Redefine Dynamic Block and Update Existing Block Instances

561 Views, 4 Replies
04-03-2014 01:26 PM

I need to Redefine Dynamic blocks and update all existing instances of the original block within a drawing to conform to the new definition. The new block definition will be read from a different dwg file/database. 

 

To accomplish this in ACAD, I run Insert, select the file containing the updated block definition (with block name matching that of existing blocks to be redefined). When blocks with the same name are present in the active drawing, I am prompted to redefine and all existing blocks are updated.

 

I found code that seemes to meant to accomplish this exact bit of work on the AutoCAD DevBlock (http://adndevblog.typepad.com/autocad/2012/05/redefining-a-block.html). I then rewrote this code which I will provide. 

 

 

When I run the method, whether it is the original code provided on the blog or my own, the new block definition is written to the database successfully. However, no existing block references are found after, so the code meant to update the geometry of existing references is never executed. The exising block instances do not reflect the changes made to the block definition after this code runs.

 

Oddly, opening an existing block instance in the block definition editor after running this code makes it clear that the new block defintion is in place. 

 

Here is my code:

 

Public Shared Function TryRedifineBlock(BlockName As String, BlockFilePath As String) As Boolean
        Dim result As Boolean = False
        Dim doc As Document = ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Using lock As DocumentLock = doc.LockDocument()
            Using tran As Transaction = doc.TransactionManager.StartTransaction()
                Try
                    Dim blockDB As Database = New Database(False, True)
                    blockDB.ReadDwgFile(BlockFilePath, FileOpenMode.OpenForReadAndReadShare, True, "")
                    Dim blockTableRecordID As ObjectId = doc.Database.Insert(BlockName, blockDB, True)
                    If Not blockTableRecordID.IsNull Then
                        Dim btr As BlockTableRecord = tran.GetObject(blockTableRecordID, OpenMode.ForRead, False, True)
                        For Each bRefID As ObjectId In btr.GetBlockReferenceIds(False, True)
                            Dim bRef As BlockReference = tran.GetObject(bRefID, OpenMode.ForWrite, False, True)
                            bRef.RecordGraphicsModified(True)
                        Next
                    End If
                    tran.Commit()
                    blockDB.Dispose()
                    result = True
                Catch ex As System.Exception
                    tran.Abort()
                    result = False
                    Try
                        EventLog.WriteEntry("DynamicBlockHelper.TryRedifineBlock", ex.GetType().Name + ": " + ex.Message + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error)
                    Catch eex As Exception

                    End Try
                End Try
            End Using
        End Using
        Return result
    End Function

 I have also attached the definition of the dynamic block I am using for testing. I apologize in advance if my ACAD termonology is off. I am fairly new to ACAD and its APIs.

 

Best Regards,

Kevin

I have never tried to write code to update a dynamic block definition and then update all the BlockReferences myself. So, I am not aware that there is simpler way to do it than re-inserting the dynamic block reference. That is, assuming the re-defined block definition has the same dynamic properties and all the dynamic properties would be set to the same value:

 

1. Find each Dynamic BlockReference;

2. read all dynamic properties' value and save them in variable(s);

3. erase the existing dynamic BlockReference;

4. Insert a new BlockReference, based in the newly updated dynamic BlockTableRecord, with the same position/scale/rotate/attributes...;

5. Set dynamic properties' value of the newly inserted dynamic BlockReference;

 

*Expert Elite*
norman.yuan
Posts: 1,049
Registered: ‎04-27-2009
Message 2 of 5 (530 Views)

Re: Redefine Dynamic Block and Update Existing Block Instances

04-04-2014 06:52 AM in reply to: kbrown

Did you debug your code by stepping through this part of code:

 

                    If Not blockTableRecordID.IsNull Then
                        Dim btr As BlockTableRecord = tran.GetObject(blockTableRecordID, OpenMode.ForRead, False, True)
                        For Each bRefID As ObjectId In btr.GetBlockReferenceIds(False, True)
                            Dim bRef As BlockReference = tran.GetObject(bRefID, OpenMode.ForWrite, False, True)
                            bRef.RecordGraphicsModified(True)
                        Next
                    End If

 

If you place a breakpoint inside the "For Each..." loop, you should be able to tell if there is any BlockRefernce is updated or not. In your case, since the block is a DYNAMIC BLOCK, if all BlockReference instances have their dynamic property/properties set to different value(s) from their original value defined in block definition, these BlockReferences will actually be the direct reference to dynamically created anonymous BlockTableRecord. You need to use BlockTableRecord.GetAnonymousBlockIds() to find out all the anonymous blockTableRecords that is derived from the dynamic BlockTableRecord, then find all the BlockReferences of all these anonymous BlockTableRecord.

 

See a very resent discussion very similar to your case:

 

http://forums.autodesk.com/t5/NET/How-to-iterate-through-block-values/m-p/4925154

 

 

Contributor
kbrown
Posts: 21
Registered: ‎10-23-2012
Message 3 of 5 (514 Views)

Re: Redefine Dynamic Block and Update Existing Block Instances

04-04-2014 11:52 AM in reply to: norman.yuan

Norman,

 

Thank you for the reply. It is truely appreciated. I revised my code based on your advice:

 

Public Shared Function TryRedifineBlock(BlockName As String, BlockFilePath As String) As Boolean
        Dim result As Boolean = False
        Dim doc As Document = ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Using lock As DocumentLock = doc.LockDocument()
            Using tran As Transaction = doc.TransactionManager.StartTransaction()
                Try
                    Dim blockDB As Database = New Database(False, True)
                    blockDB.ReadDwgFile(BlockFilePath, FileOpenMode.OpenForReadAndReadShare, True, "")
                    Dim blockTableRecordID As ObjectId = doc.Database.Insert(BlockName, blockDB, True)
                    If Not blockTableRecordID.IsNull Then
                        Dim btr As BlockTableRecord = tran.GetObject(blockTableRecordID, OpenMode.ForRead, False, True)
                        For Each bRefID As ObjectId In btr.GetBlockReferenceIds(False, True)
                            Dim bRef As BlockReference = tran.GetObject(bRefID, OpenMode.ForWrite, False, True)
                            bRef.RecordGraphicsModified(True)
                        Next
                        If btr.IsDynamicBlock Then
                            For Each dynBtr As ObjectId In btr.GetAnonymousBlockIds()
                                Dim dynBr As BlockTableRecord = DirectCast(tran.GetObject(dynBtr, OpenMode.ForRead), BlockTableRecord)
                                For Each dynBlkID As ObjectId In dynBr.GetBlockReferenceIds(True, True)
                                    Dim dynBlkRef As BlockReference = tran.GetObject(dynBlkID, OpenMode.ForWrite, False, True)
                                    dynBlkRef.RecordGraphicsModified(True)
                                Next
                            Next
                        End If
                    End If
                    tran.Commit()
                    blockDB.Dispose()
                    result = True
                Catch ex As System.Exception
                    tran.Abort()
                    result = False
                    Try
                        EventLog.WriteEntry("DynamicBlockHelper.TryRedifineBlock", ex.GetType().Name + ": " + ex.Message + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error)
                    Catch eex As System.Exception

                    End Try
                End Try
            End Using
        End Using
        Return result
    End Function

 

Now block reference IDs are indeed found. However, the new block definition is not applied to the "dynamically created block definitions", so the call to RecordGraphicsModified has not effect and the method still does not work as intended.

 

How would I go about updating these dynamically generated block definitions with the updated definitition from the secondary database? Thank you in advance.

 

Best Regards,

Kevin

 

*Expert Elite*
norman.yuan
Posts: 1,049
Registered: ‎04-27-2009
Message 4 of 5 (509 Views)

Re: Redefine Dynamic Block and Update Existing Block Instances

04-04-2014 12:22 PM in reply to: kbrown

I have never tried to write code to update a dynamic block definition and then update all the BlockReferences myself. So, I am not aware that there is simpler way to do it than re-inserting the dynamic block reference. That is, assuming the re-defined block definition has the same dynamic properties and all the dynamic properties would be set to the same value:

 

1. Find each Dynamic BlockReference;

2. read all dynamic properties' value and save them in variable(s);

3. erase the existing dynamic BlockReference;

4. Insert a new BlockReference, based in the newly updated dynamic BlockTableRecord, with the same position/scale/rotate/attributes...;

5. Set dynamic properties' value of the newly inserted dynamic BlockReference;

 

Contributor
kbrown
Posts: 21
Registered: ‎10-23-2012
Message 5 of 5 (493 Views)

Re: Redefine Dynamic Block and Update Existing Block Instances

04-05-2014 12:09 PM in reply to: norman.yuan

I considered this solution, but I had hoped to find an alternative. Perhaps what you suggest is the best solution, since it will allow me complete control over copying Block Property states and Attribute states.

 

Still, I can acheive my aim by running the insert command in autocad, selecting the new block defintion, then redefining when prompted to. 

 

I did find a post (http://forums.autodesk.com/t5/Dynamic-Blocks/Redefining-Updating-Dynamic-Blocks/td-p/1623916/highlig... in the Dynamic Block section of the forums which suggests a course of action which might be achieved using .net:

 

1) RENAME block to be updated; 2) Insert new block; 3) use BLOCKREPLACE to 
update renamed block; 4) Use ATTSYNC if necessary.

 

However, I think I will implement the method you suggest because it offers me more control and is very likely to work as expect.

 

Thank you very much for you insights. I will post my code after it is tested.

 

Best Regards,

Kevin

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Are You Going To Be @ AU 2014? Feel free to drop by our AU topic post and share your plans, plug a class that you're teaching, or simply check out who else from the community might be in attendance. Ohh and don't forgot to stop by the Autodesk Help | Learn | Collaborate booths in the Exhibit Hall and meet our community team if you get a chance!