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

Redefine Dynamic Block and Update Existing Block Instances

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
kbrown
5137 Views, 8 Replies

Redefine Dynamic Block and Update Existing Block Instances

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

8 REPLIES 8
Message 2 of 9
norman.yuan
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

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 9
kbrown
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

 

Message 4 of 9
norman.yuan
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;

 

Norman Yuan

Drive CAD With Code

EESignature

Message 5 of 9
kbrown
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

Message 6 of 9
claus.frederiksen
in reply to: kbrown

Hi

Maybe you figured it out, but if you change the dynamic update part:

Dim dynBlkRef As BlockReference = tran.GetObject(dynBlkID, OpenMode.ForWrite, False, True)
dynBlkRef.RecordGraphicsModified(True)

with this:

Dim dynBlkRef As BlockReference = tran.GetObject(dynBlkID, OpenMode.ForWrite, False, True)
dynBlkRef.ResetBlock()
dynBlkRef.RecordGraphicsModified(True)

Your dynamic block reference will be updated. It will however have the default dynamic values.
Message 7 of 9
henk.loonstra
in reply to: norman.yuan

I use norman's 5 steps to update Dynamic BlockReferences after I changed the BlockDefinition.

Be aware of the Dynamic Property "Origin", which appears in a Dynamic Block when a "Length" parameter and/or a "Stretch" action is added.

 

Reading its value (always (0,0,0)?) and setting it again will mess up all your anonymous References.

Message 8 of 9
u.steinmetz
in reply to: kbrown

You have to call updateAnonymousBlocks() after you set the saved dynamic properties to the replaced dynamic block, e.g.

 

        AcDbDynBlockReference mm_dynBlockReference (blockReference);
        bool mm_isDynamic = mm_dynBlockReference.isDynamicBlock();
        AcDbDynBlockReferencePropertyArray mm_dynamicProperties;
        if (mm_isDynamic)
        {
            mm_dynBlockReference.getBlockProperties(mm_dynamicProperties);

            for (int mm_index = 0; mm_index < mm_dynamicProperties.length(); mm_index++)
            {
                enString mm_propertyName = mm_dynamicProperties[mm_index].propertyName();

                MapPropertyNameToValue::const_iterator mm_iter = mapValues.find(mm_propertyName);
                if (mm_iter != mapValues.end())
                {
                    mm_dynamicProperties[mm_index].setValue(mm_iter->second);
                }
            }

            AcDbObjectId dynBlockDefinitionId = mm_dynBlockReference.dynamicBlockTableRecord();
            if (!dynBlockDefinitionId.isNull())
            {
                AcDbDynBlockTableRecord dynamicBlockDefinition(dynBlockDefinitionId);
                dynamicBlockDefinition.updateAnonymousBlocks();
            }

 

There should be a similar method in .net.

Tags (1)
Message 9 of 9

You're replying to a 3 year-old post, in case you didn't notice.

 


@u.steinmetz wrote:

You have to call updateAnonymousBlocks() after you set the saved dynamic properties to the replaced dynamic block, e.g.

 


 

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