Code Red > .NET

Delete Block References and Definitions

(1/3) > >>

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