Code Red > .NET
Delete Block References and Definitions
DBARANAS:
I have been working on this for some time. It is supposed to making test blocks programmably and erasing them programmably
Create some solids
Add them to their own Block Definitions
Add the block Definitions to their own Block References
Then go back and erase everything....
I can create blocks OK, but when I erase everything the block reference still lives in the db and a manual purge has to be done to really kill it, although things erase off the screen as expected.
I need to erase the block definition and reference from the database completely or I will get ghosts of deleted solids back when I make the block reference again.
I made this is stripped down version for testing.
In the test app (sub adjBlockDef) I can't get the block definition back from a handle.
I think I might be going about getting it back the wrong way. It's not making much sense as I have to get at the db.BlockTableId twice in the same sub of get a crash. Open 1st for read then again for write.
I hate to post lot's of code but it is stripped down to just do the 4 things it is supposed to. If anyone could give a quick look I would appreciate it.
--- Code: --- Public Sub BlockTest()
Dim BlockDefHnd(5) As String
Dim BlockRefHnd(5) As String
Dim BlockName(5) As String
Dim i As Integer = 0
Dim j As Double = 10
For i = 0 To 5
BlockDefHnd(i) = vbNullString
BlockRefHnd(i) = vbNullString
BlockName(i) = "Blockname" & CStr(i)
Next
'Make some block references each containing 1 solid and 1 block definition each
For i = 0 To 5
addSomething(i * 10, i * 10, i * 10, BlockName(i), BlockDefHnd(i))
addBlockRef(BlockName(i), BlockRefHnd(i))
Next
'No go and remove everything
i = 0
For i = 0 To 5
adjBlockRef(BlockRefHnd(i))
adjBlockDef(BlockDefHnd(i))
Next
End Sub
Public Sub addSomething(ByVal x As Double, _
ByVal y As Double, _
ByVal z As Double, _
ByVal BlockName As String, _
ByRef BlockDefHnd As String)
Dim aPnt As New Point3d(0, 0, 0)
Dim bPnt As New Point3d(55, 0, 0)
Dim cPnt As New Point3d(55, 5, 0)
Dim dPnt As New Point3d(0, 5, 0)
Dim colregion As DBObjectCollection = New DBObjectCollection()
Dim colPoly As DBObjectCollection = New DBObjectCollection()
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim region As DatabaseServices.Region = New DatabaseServices.Region()
Dim trans As Transaction = db.TransactionManager.StartTransaction()
Dim pntCol As New Point3dCollection
Try
Dim bt As BlockTable = DirectCast(trans.GetObject(db.BlockTableId, DatabaseServices.OpenMode.ForRead, True), BlockTable)
If bt Is Nothing Then Return
Dim doclock As DocumentLock = AcAp.DocumentManager.MdiActiveDocument.LockDocument()
Dim btr As BlockTableRecord = DirectCast(trans.GetObject(bt(BlockTableRecord.ModelSpace), DatabaseServices.OpenMode.ForWrite, False), BlockTableRecord)
If btr Is Nothing Then Return
pntCol.Add(aPnt) : pntCol.Add(bPnt) : pntCol.Add(cPnt) : pntCol.Add(dPnt)
Dim plRegion As New Polyline3d(Poly3dType.SimplePoly, pntCol, True)
'create a region from the polyline
colPoly.Add(plRegion)
colregion = DatabaseServices.Region.CreateFromCurves(colPoly)
region = CType(colregion(0), DatabaseServices.Region)
'create the solid
Dim solid As Solid3d = New Solid3d()
solid.Extrude(region, 5, 0)
Dim vector As New Vector3d(x, y, z)
Dim matrix As Matrix3d = Matrix3d.Displacement(vector)
solid.TransformBy(solid.Ecs.PostMultiplyBy(matrix))
'need this to get at db again for write...have to do this or get a crash!!
Dim btDef As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForWrite)
Dim BlockDefId As ObjectId
If (bt.Has(BlockName)) Then
BlockDefId = btDef(BlockName) 'Already there...no need to recreate it
Dim BlockDef As BlockTableRecord = trans.GetObject(bt(BlockName), OpenMode.ForWrite)
BlockDef.AppendEntity(solid)
trans.AddNewlyCreatedDBObject(solid, True)
BlockDefHnd = BlockDef.ObjectId.Handle.ToString()
Else 'Create a new block definition
Dim BlockDef As BlockTableRecord = New BlockTableRecord()
BlockDef.Name = BlockName
BlockDefId = btDef.Add(BlockDef)
trans.AddNewlyCreatedDBObject(BlockDef, True)
BlockDef.AppendEntity(solid)
trans.AddNewlyCreatedDBObject(solid, True)
BlockDefHnd = BlockDef.ObjectId.Handle.ToString()
End If
trans.Commit()
doclock.Dispose()
colPoly.Dispose()
colregion.Dispose()
plRegion.Dispose()
pntCol.Dispose()
region.Dispose()
solid.Dispose()
Catch ex As Autodesk.AutoCAD.Runtime.Exception
trans.Abort()
MsgBox(ex.StackTrace)
Finally
trans.Dispose()
End Try
End Sub
Public Sub addBlockRef(ByVal BlockName As String, ByRef BlockRefHnd As String)
Dim db As Database = HostApplicationServices.WorkingDatabase()
Dim trans As Transaction = db.TransactionManager.StartTransaction()
Dim doclock As DocumentLock = AcAp.DocumentManager.MdiActiveDocument.LockDocument()
Dim block As BlockReference = Nothing
Try
Dim bt As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForWrite)
Dim mspace As BlockTableRecord = trans.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
block = New BlockReference(New Point3d(0, 0, 0), bt(BlockName))
mspace.AppendEntity(block)
trans.AddNewlyCreatedDBObject(block, True)
BlockRefHnd = block.ObjectId.Handle.Value.ToString() 'return handle to calling sub
trans.Commit()
doclock.Dispose()
Catch ex As Autodesk.AutoCAD.Runtime.Exception
trans.Abort()
MsgBox(ex.StackTrace)
Finally
trans.Dispose()
End Try
End Sub
Public Sub adjBlockRef(ByVal BlockRefHnd As String)
Dim db As Database = HostApplicationServices.WorkingDatabase()
Dim ed As EditorInput.Editor = AcAp.DocumentManager.MdiActiveDocument.Editor()
Dim trans As Transaction = db.TransactionManager.StartTransaction()
Try
Dim id As ObjectId = db.GetObjectId(False, New Handle(Convert.ToInt64(BlockRefHnd)), 0)
Dim doclock As DocumentLock = AcAp.DocumentManager.MdiActiveDocument.LockDocument()
Dim Block As BlockReference = DirectCast(trans.GetObject(id, DatabaseServices.OpenMode.ForWrite), BlockReference)
Dim br As BlockTableRecord = DirectCast(trans.GetObject(Block.BlockTableRecord, DatabaseServices.OpenMode.ForRead, False), BlockTableRecord)
For Each obj As ObjectId In br
Dim ent As Entity = DirectCast(trans.GetObject(obj, DatabaseServices.OpenMode.ForWrite), Entity)
ent.ObjectId.Handle.ToString()
ent.Erase()
Next obj
Block.Erase()
BlockRefHnd = vbNullString
trans.Commit()
db.Dispose()
doclock.Dispose()
Catch ex As Autodesk.AutoCAD.Runtime.Exception
trans.Abort()
MsgBox(ex.StackTrace)
Finally
trans.Dispose()
End Try
End Sub
Public Sub adjBlockDef(ByVal BlockDefHnd As String)
Dim db As Database = AcAp.DocumentManager.MdiActiveDocument.Database
Dim ed As EditorInput.Editor = AcAp.DocumentManager.MdiActiveDocument.Editor()
Dim trans As Transaction = db.TransactionManager.StartTransaction()
Try
Dim id As ObjectId = db.GetObjectId(False, New Handle(Convert.ToInt64(BlockDefHnd)), 0)
Dim doclock As DocumentLock = AcAp.DocumentManager.MdiActiveDocument.LockDocument()
Dim BlockDef As BlockReference = DirectCast(trans.GetObject(id, DatabaseServices.OpenMode.ForWrite), BlockReference)
BlockDef.Erase()
BlockDefHnd = vbNullString
trans.Commit()
db.Dispose()
doclock.Dispose()
Catch ex As AcRu.Exception
trans.Abort()
MsgBox(ex.StackTrace)
Finally
trans.Dispose()
End Try
End Sub
--- End code ---
DBARANAS:
I found a mistake
BlockDefHnd = BlockDef.ObjectId.Handle.ToString() .....should be
BlockDefHnd = BlockDef.ObjectId.Handle.Value.ToString()
....Now it works for the first pass. When I try the whole thing again I get eWasErased errors on these 2 lines. Interestingly on the second pass where it checks if block definitions exist ....(bt.Has(BlockName))... they do not exist as is expected because they got erased at the end of the first pass. So they get made again.
There has got to be something funny going on with the databases. I must be missing something being put where I can't find it again
sub adjBlockRef.......
Dim br As BlockTableRecord = DirectCast(trans.GetObject(Block.BlockTableRecord, DatabaseServices.OpenMode.ForWrite, False), BlockTableRecord)
end sub
sub adjBlockDef.......
Dim BlockDef As BlockTableRecord = trans.GetObject(bt(BlockName), OpenMode.ForWrite)
end sub
Glenn R:
A very quick scan revealed some things you might consider:
You open the blocktable for read earlier, then you open it for write with another transaction statement.
You don't need to do that, you can do it like this:
if (!blockTable.IsWriteEnabled)
blockTable.UpgradeOpen();
Cheers,
Glenn.
DBARANAS:
You open the blocktable for read earlier, then you open it for write with another transaction statement.
You don't need to do that, you can do it like this:
if (!blockTable.IsWriteEnabled)
blockTable.UpgradeOpen();
Thanks Glenn
I pasted it in ........
--- Code: --- 'need this to get at db again for write...have to do this or get a crash!!
If Not bt.IsWriteEnabled Then bt.UpgradeOpen()
'Dim btDef As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForWrite)
Dim BlockDefId As ObjectId
If (bt.Has(BlockName)) Then
BlockDefId = bt(BlockName) 'Already there...no need to recreate it
Dim BlockDef As BlockTableRecord = trans.GetObject(bt(BlockName), OpenMode.ForWrite)
BlockDef.AppendEntity(solid)
trans.AddNewlyCreatedDBObject(solid, True)
BlockDefHnd = BlockDef.ObjectId.Handle.Value.ToString()
Else 'Create a new block definition
Dim BlockDef As BlockTableRecord = New BlockTableRecord()
BlockDef.Name = BlockName
BlockDefId = bt.Add(BlockDef)
trans.AddNewlyCreatedDBObject(BlockDef, True)
BlockDef.AppendEntity(solid)
trans.AddNewlyCreatedDBObject(solid, True)
BlockDefHnd = BlockDef.ObjectId.Handle.Value.ToString()
End If
--- End code ---
Unfortunately It stopped the loop from going through the first time.
It seems that I have the db objects (I can see all the properties of them when I step through.
On the second pass I can create everything again, but the second time I try to delete those block ref's and def's I get the eWasErased error when I try to cast them back. I am wondering about using a key so I can skip a few steps
Glenn R:
Have a look here:
http://www.theswamp.org/index.php?topic=12123.msg150999#msg150999
Navigation
[0] Message Index
[#] Next page
Go to full version