Multiple Undos required under a single transaction

Multiple Undos required under a single transaction

SRSDS
Advisor Advisor
805 Views
2 Replies
Message 1 of 3

Multiple Undos required under a single transaction

SRSDS
Advisor
Advisor

I've asked this before but I confused the topic when I posted code that was unrelated.

Inserting multiple blocks and changing their dynamic block properties under the one transactions requires multiple undo's to reverse a single command.

I think if I change to StartOpenCloseTransaction from StartTransaction it might fix it. 

The problem with doing that is that that I get an eWasOpenForRead on the line:

 

 destdb.WblockCloneObjects(ids, destdb.BlockTableId, iMap, DuplicateRecordCloning.Replace, False)

 

Which doesn't occur when using StartTransaction.

 

    Public Sub ImportBlock(ByVal blockFileName As String, ByVal Blockname As String, ByRef trans As Transaction)
        Dim destdb As Database = Application.DocumentManager.MdiActiveDocument.Database
        Try
            Using sourcedb As New Database(False, True)
                sourcedb.ReadDwgFile(blockFileName, FileShare.ReadWrite, True, "")
                Dim ids As New ObjectIdCollection()
                Using sourceTrans As Transaction = sourcedb.TransactionManager.StartOpenCloseTransaction()
                    Dim sourceBT As BlockTable
                    sourceBT = DirectCast(sourceTrans.GetObject(sourcedb.BlockTableId, OpenMode.ForRead), BlockTable)
                    If sourceBT.Has(Blockname) Then
                        ids.Add(sourceBT(Blockname))
                    Else
                        MsgBox("ImportBlock - Blockname not found in file" & vbCrLf & "Block must be incorrectly named.")
                        Cancel = True
                        Return
                    End If
                End Using
                'if found, add the block
                If ids.Count <> 0 Then
                    'get the current drawing database
                    Dim iMap As New IdMapping()
                    destdb.WblockCloneObjects(ids, destdb.BlockTableId, iMap, DuplicateRecordCloning.Replace, False)
                End If
            End Using
        Catch ex As Exception
            Cancel = True
            If ex.Message = "eFileSharingViolation" Then
                MsgBox("Close Blocks Drawing. ", MsgBoxStyle.Exclamation)
            ElseIf ex.Message = "eFileNotFound" Then
                MsgBox("Block File Not Found. ", MsgBoxStyle.Exclamation)
            Else
                MsgBox(Reflection.MethodBase.GetCurrentMethod.Name() + " Exception: " + ex.Message)
            End If
        End Try
    End Sub

 

Hope someone can help.

 

0 Likes
Accepted solutions (1)
806 Views
2 Replies
Replies (2)
Message 2 of 3

_gile
Consultant
Consultant

Hi,

 

You should try calling sourceDb.WBlockCloneObjects() instead of destDb.WBlockCloneObjects() and do it outside of the transaction.

 

Here's an example which returns the ObjectId of the imported BlockTableRecord (or ObjectId.Null).

        public static ObjectId TryImportBlock(string fileName, string blockName)
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var destDb = doc.Database;
            var ed = doc.Editor;
            try
            {
                using (var sourceDb = new Database(false, true))
                {
                    sourceDb.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, null);
                    var ids = new ObjectIdCollection();

                    using (var tr = sourceDb.TransactionManager.StartOpenCloseTransaction())
                    {
                        var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                        if (!bt.Has(blockName))
                        {
                            ed.WriteMessage("Block not found");
                            return ObjectId.Null;
                        }
                        ids.Add(bt[blockName]);
                        tr.Commit();
                    }

                    var mapping = new IdMapping();
                    sourceDb.WblockCloneObjects(ids, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
                    return mapping[ids[0]].Value;
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage(ex.Message);
                return ObjectId.Null;
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 3

SRSDS
Advisor
Advisor
Accepted solution

Found the fix.

Don't understand why there was a problem to begin with but...

 

I have been starting a 'master' transaction on each command that gets fed into each subroutine

Given that most of the routines require a transaction I figured that was sensible.

 

The 'master' transaction was used to insert then modified multiple blocks.

The combination of inserting then modify dynamic block properties under a master transaction caused an undo operation required for each. Inserting the blocks alone wasn't a problem but modifying them was.

 

Creating an independent transaction for inserting each block seems to have fixed it.

 

Massive headache/confusion solved.

  

 

0 Likes