Author Topic: need help moving newly added xref  (Read 3362 times)

0 Members and 1 Guest are viewing this topic.

commodore

  • Newt
  • Posts: 51
need help moving newly added xref
« on: December 03, 2010, 03:32:41 PM »
Thanks to code I found here I managed to add an Xref to my drawing, now I need to move that newly added Xref to a new position and I'm having a problem with that.
A portion of the full code follows

Code: [Select]
        For Each fileName As String In fileNames
            Dim options As PromptPointOptions = New PromptPointOptions(("Pick insertion point for " _
                            + (fileName + ": ")))
            options.AllowNone = False
            Dim pt As PromptPointResult = ed.GetPoint(options)
            If (pt.Status <> PromptStatus.OK) Then
                'TODO: Warning!!! continue If
            End If
            Dim xrefScale As Double = getDwgScale(fileName)
            Dim scaleFactor As Double = (dimScale / xrefScale)
            Dim tr As Transaction = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction
            Dim xrefId As ObjectId = db.AttachXref(fileName, Path.GetFileNameWithoutExtension(fileName))
            Dim blockRef As BlockReference = New BlockReference(pt.Value, xrefId)
            Dim blockTblRec As BlockTableRecord = CType(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
            blockRef.ScaleFactors = New Scale3d(scaleFactor, scaleFactor, scaleFactor)
            blockRef.Layer = "0"
            blockTblRec.AppendEntity(blockRef)
            tr.AddNewlyCreatedDBObject(blockRef, True)
            tr.Commit()


            '' Get the current document and database
            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            Dim acCurDb As Database = acDoc.Database

            '' Start a transaction(again?)
            Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
                '' Open the Block table for read
                Dim acBlkTbl As BlockTable
                acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
                '' Open the Block table record Model space for read
                Dim acBlkTblRec As BlockTableRecord
                acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForRead)
                Dim bref As BlockReference
                '' Step through the Block table record
                For Each acObjId As ObjectId In acBlkTblRec
                    bref = acTrans.GetObject(acObjId, OpenMode.ForWrite, False, True) '<========================== ERROR HERE
                    bref.Position = bref.Position.TransformBy(Matrix3d.Displacement(New Vector3d(100, 100, 0)))
                    acTrans.Commit()
                Next
                '' Dispose of the transaction
                acTrans.Dispose()
            End Using
        Next

On the first run in a blank drawing it runs fine, Inserts and moves Xref, on subsequent runs I get an error "Operation is not valid due to the current state of the object" at the line indicated, yet I can continue past it and it still inserts and moves an Xref.

It feels like I'm trying to get and move the last Xref inserted the "hard way".
What is the "easy way" that I should be moving the xref?

T.Willey

  • Needs a day job
  • Posts: 5251
Re: need help moving newly added xref
« Reply #1 on: December 03, 2010, 04:14:34 PM »
The top section looks fine, but the bottom section looks like you are stepping though the BlockTableRecord of model space, and trying to cast all entities to the type of BlockReference.  I would think it should error if you are looking at a line, or any other entity besides a block reference.  Maybe you should test each entity, and see if it's a block reference before casting it as that type.  I don't know VB, but in C# it might look something like ( written in the post, so no checking )

foreach ( ObjectId id in BlkTblRec ) {
    Entity Ent = Trans.GetObject( id, OpenMode.ForRead) as Entity;
    if ( !Ent is BlockReference ) continue;
    BlockReference BlkRef = Trans.GetObject( id, OpenMode.ForRead ) as BlockReference;
    // do what you want here ....
}
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

commodore

  • Newt
  • Posts: 51
Re: need help moving newly added xref
« Reply #2 on: December 04, 2010, 07:53:22 AM »
Thanks, I changed my bottom section per your advise but I'm still getting the same error. Again, it runs fine in a blank drawing the first time its run and it places one xref in and moves it. Any additional times it is run in the same drawing it will error but it still inserts and moves another xref.
Is there a way to just get the last object or Xref that I inserted directly instead of going through the entire blocktable?
 
altered code...
Code: [Select]
            '' Get the current document and database
            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            Dim acCurDb As Database = acDoc.Database

            '' Start a transaction(again?)
            Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
                '' Open the Block table for read
                Dim acBlkTbl As BlockTable
                acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
                '' Open the Block table record Model space for read
                Dim acBlkTblRec As BlockTableRecord
                acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForRead)
                '' Step through the Block table record
                For Each id As ObjectId In acBlkTblRec
                    Dim Ent As Entity = CType(acTrans.GetObject(id, OpenMode.ForRead), Entity) '<============= SAME ERROR NOW APPEARS HERE !
                    If (Ent.GetType.ToString = "Autodesk.AutoCAD.DatabaseServices.BlockReference") Then
                        Dim BlkRef As BlockReference = CType(acTrans.GetObject(id, OpenMode.ForWrite), BlockReference)
                        BlkRef.Position = BlkRef.Position.TransformBy(Matrix3d.Displacement(New Vector3d(100, 100, 0)))
                    End If
                    acTrans.Commit()
                Next
            End Using
        Next

commodore

  • Newt
  • Posts: 51
Re: need help moving newly added xref
« Reply #3 on: December 04, 2010, 10:07:20 AM »
Ok, I got it but I'm not sure I understand. maybe I misunderstood what "commit" does.
I got it to work by moving "actrans.commit()" outside my For-Next loop. I thought "commit" just commited any changes to the databases but left the transactions open but it looks like it was closing my transaction.
Someone want to set me straight on what "commit" really does?

working code...
Code: [Select]
           '' Start a transaction(again?)
            Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
                '' Open the Block table for read
                Dim acBlkTbl As BlockTable
                acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
                '' Open the Block table record Model space for read
                Dim acBlkTblRec As BlockTableRecord
                acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForRead)
                '' Step through the Block table record
                For Each id As ObjectId In acBlkTblRec
                    Dim Ent As Entity = CType(acTrans.GetObject(id, OpenMode.ForRead), Entity)
                    If Ent.GetType.Name = "BlockReference" Then
                        'If (Ent.GetType.ToString = "Autodesk.AutoCAD.DatabaseServices.BlockReference") Then
                        Dim BlkRef As BlockReference = CType(acTrans.GetObject(id, OpenMode.ForWrite), BlockReference)
                        BlkRef.Position = BlkRef.Position.TransformBy(Matrix3d.Displacement(New Vector3d(100, 100, 0)))
                    End If
                    'acTrans.Commit()
                Next
                acTrans.Commit() '<============= MOVED COMMIT TO HERE AND NOW IT WORKS !
            End Using

vegbruiser

  • Guest
Re: need help moving newly added xref
« Reply #4 on: December 06, 2010, 06:50:28 AM »
As I understand it (and I might be wrong) no entity will be modified or changed (permanently) until you commit a transaction. And the act of committing the transaction tells AutoCAD you no longer need it.

I have seen people also ".Dispose();" transactions too, but I thought that enclosing the Transaction in a "Using" loop (as you have done) did that for you when the loop ends?

Jeff H

  • Needs a day job
  • Posts: 6150
Re: need help moving newly added xref
« Reply #5 on: December 08, 2010, 01:34:39 AM »
Maybe this will help and then see if you can reply back why you get the error

Someone correct me if I am wrong

Separate the actual transaction and the objects opened during the transaction.

The Commit does not close the transaction, it Commits all the changes made to the DBObjects and closes all DBObjects that were open during the transaction.


I threw this together real quick as a example

You do not really need to worry about this first one. You can use the Transaction.GetAllObjects() function(VB) or method(C#) that returns a DBObjectCollection of all the currently opened objects
in the transaction.
This method just writes all open objects in the transaction to the command line.
The code pasted later uses this and passes in Transaction.GetAllObjects() and calls it at different times to write them to the command line.
Code: [Select]

Public Sub OpenObjectsToCommandLine(ByVal dbObjColl As DBObjectCollection)

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction


                For Each dbObj As DBObject In dbObjColl
                    Dim objId As ObjectId = dbObj.ObjectId
                    Try
                        Dim ent As Entity = objId.GetObject(OpenMode.ForRead)

                        If TypeOf ent Is BlockReference Then
                            Dim bref As BlockReference = ent
                            ed.WriteMessage(vbCrLf & bref.Name & "   " & bref.ObjectId.ToString())
                        End If
                    Catch ex As System.Exception
                        ed.WriteMessage(objId.GetType.ToString() & objId.ToString())
                    End Try

                 

                Next

                trx.Commit()

            End Using
        End Sub


This one iterates through Model Space and moves all BlockReferences
Notice OpenObjectsToCommandLine() called after Commit causes a error
Code: [Select]
<CommandMethod("TrxCommit")> _
        Public Sub TrxCommit()

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction

                Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
                Dim btrMs As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)

                For Each objId As ObjectId In btrMs
                    Dim ent As Entity = objId.GetObject(OpenMode.ForRead)
                    If TypeOf ent Is BlockReference Then
                        Dim bref As BlockReference = ent
                        bref.UpgradeOpen()
                        bref.Position = bref.Position.TransformBy(Matrix3d.Displacement(New Vector3d(100, 100, 0)))
                    End If

                Next
                OpenObjectsToCommandLine(trx.GetAllObjects())
                trx.Commit() '''' Commit

                'OpenObjectsToCommandLine(trx.GetAllObjects())  '' Will cause error

            End Using

        End Sub

This one is just like the previous except it does not commit it in a nested transaction so nothing is committed or moved and it calls OpenObjectsToCommandLine in the For Next loop so you can see it build up
Code: [Select]
<CommandMethod("TrxCommit2")> _
        Public Sub TrxCommit2()

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction
                TrxNoCommit()
                trx.Commit()
            End Using

        End Sub
     
        Public Sub TrxNoCommit()

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction

                Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
                Dim btrMs As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)

                For Each objId As ObjectId In btrMs
                    Dim ent As Entity = objId.GetObject(OpenMode.ForRead)
                    If TypeOf ent Is BlockReference Then
                        Dim bref As BlockReference = ent
                        bref.UpgradeOpen()
                        bref.Position = bref.Position.TransformBy(Matrix3d.Displacement(New Vector3d(100, 100, 0)))
                    End If
                    '''' Does Not Commit
                    OpenObjectsToCommandLine(trx.GetAllObjects())
                Next

            End Using

        End Sub

This last is just last the first and calls Dispose after Commit to show everthing still moves

Code: [Select]
<CommandMethod("TrxCommit3")> _
        Public Sub TrxCommit3()

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction
                TrxDispose()
                trx.Commit()
            End Using

        End Sub

        Public Sub TrxDispose()

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction

                Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
                Dim btrMs As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)

                For Each objId As ObjectId In btrMs
                    Dim ent As Entity = objId.GetObject(OpenMode.ForRead)
                    If TypeOf ent Is BlockReference Then
                        Dim bref As BlockReference = ent
                        bref.UpgradeOpen()
                        bref.Position = bref.Position.TransformBy(Matrix3d.Displacement(New Vector3d(100, 100, 0)))
                    End If
                    OpenObjectsToCommandLine(trx.GetAllObjects())
                Next
                trx.Commit() '''' Commit
                trx.Dispose() '''' Dispose

            End Using

        End Sub