Ed Jobe very kindly emailed me some suggestions for the blog (thanks Ed ). After we’d chatted for a while, he also asked a quick coding question:
“Can you post a sample to redefine a block? I've seen some for inserting from file, but I haven't seen one for redefining. The db.Insert() function only creates new block table records.”
Here is some simple code demonstrating how to insert a DWG into your current drawing as a block named 'TEST'. If the a block named 'TEST' already exists in your drawing, then it is redefined:
<CommandMethod("ReplaceBlock")> _
Public Sub ReplaceBlock()
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim blockName As String = "TEST"
Dim blkDb As Database = New Database(False, True)
blkDb.ReadDwgFile("C:\\Temp\\TEST.dwg",
System.IO.FileShare.Read, True, "")
Using Tx As Transaction = db.TransactionManager.StartTransaction()
Dim blockTable As BlockTable =
Tx.GetObject(db.BlockTableId, OpenMode.ForRead, False, True)
Dim btrId As ObjectId = db.Insert(blockName, blkDb, True)
If btrId <> ObjectId.Null Then
Dim btr As BlockTableRecord =
Tx.GetObject(btrId,
OpenMode.ForRead, False, True)
Dim brefIds As ObjectIdCollection =
btr.GetBlockReferenceIds(False, True)
For Each id As ObjectId In brefIds
Dim bref As BlockReference =
Tx.GetObject(id, OpenMode.ForWrite, False, True)
bref.RecordGraphicsModified(True)
Next
End If
Tx.Commit()
End Using
blkDb.Dispose()
End Sub
Alternatively, if you want to programmatically edit the contents of a block (not inserting from another database), you can open up the BlockTableRecord for write, erase all the current entities it holds, and add your new ones. Here is a quick edit to the above function to redefine the block to just contain a single line:
<CommandMethod("ReplaceBlock")> _
Public Sub ReplaceBlock()
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim blockName As String = "TEST"
Using Tx As Transaction = db.TransactionManager.StartTransaction()
Dim blockTable As BlockTable =
Tx.GetObject(db.BlockTableId, OpenMode.ForRead, False, True)
If (blockTable.Has(blockName)) Then
Dim btr As BlockTableRecord =
Tx.GetObject(blockTable(blockName),
OpenMode.ForWrite, False, True)
'Erase all entities in btr
For Each id As ObjectId In btr
Dim ent As Entity = id.GetObject(OpenMode.ForWrite)
ent.Erase()
Next
'Add new entities to btr
Dim aLine As New Line(New Point3d(50, 50, 0), New Point3d(100, 100, 0))
btr.AppendEntity(aLine)
Tx.AddNewlyCreatedDBObject(aLine, True)
Dim brefIds As ObjectIdCollection =
btr.GetBlockReferenceIds(False, True)
'Update blockrefs to display new graphics
For Each id As ObjectId In brefIds
Dim bref As BlockReference =
Tx.GetObject(id, OpenMode.ForWrite, False, True)
bref.RecordGraphicsModified(True)
Next
Tx.Commit()
End If
End Using
End Sub
Notice that in both code snippets we iterate through all the BlockReferences associated with the BlockTableRecord we’re editing and call their RecordGraphicsModified method. This is because a BlockTableRecord doesn’t automatically notify its BlockReferences when it is edited, so we have to explicitly tell the BlockReferences to regenerate their graphics.
Hope this is helpful Ed.
______________________
Updated May 7th 2012 to incorporate Norman Yuan's comment. I prefer calling RecordGraphicsModified on the BlockReference rather than to Regen the entire drawing, but that is personal choice.
