eWasOpenForWrite

eWasOpenForWrite

SRSDS
Advisor Advisor
3,758 Views
6 Replies
Message 1 of 7

eWasOpenForWrite

SRSDS
Advisor
Advisor

Hi,

 

Can someone please try to spot what's wrong to get an eWasOpenForWrite on the line

 db.Clayer = acLyrTbl("DIM")

 

 Private Sub doc_CommandWillStart(ByVal sender As Object, ByVal e As CommandEventArgs)
        If PauseEvents = False Then
            If e.GlobalCommandName = "DIMLINEAR" Or e.GlobalCommandName = "DIMALIGNED" Or e.GlobalCommandName = "DIMANGULAR" Or e.GlobalCommandName = "DIMCONTINUE" Then
                Using trans As Transaction = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartOpenCloseTransaction : trcnt = trcnt + 1
                    Dim LayerName As String = "DIM"
                    Dim lyrId As ObjectId = Nothing
                    Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
                    Try
                        Dim lyrTbl As LayerTable = trans.GetObject(db.LayerTableId, OpenMode.ForRead, False)
                        Using ltypTbl As LinetypeTable = trans.GetObject(db.LinetypeTableId, OpenMode.ForRead, False)
                                Using myLayer As LayerTableRecord = New LayerTableRecord
                                If lyrTbl.Has(LayerName) = False Then
                                    myLayer.Name = LayerName
                                    lyrTbl.UpgradeOpen()
                                    lyrTbl.Add(myLayer)
                                    trans.AddNewlyCreatedDBObject(myLayer, True)
                                End If
                                lyrId = lyrTbl.Item(LayerName)
                                End Using
                            End Using
                        Dim acLyrTbl As LayerTable = trans.GetObject(db.LayerTableId, OpenMode.ForRead)
                        If acLyrTbl.Has("DIM") = True Then
                            db.Clayer = acLyrTbl("DIM")
                        End If
                        trans.Commit() 
                    Catch ex As Exception
                    MsgBox(Reflection.MethodBase.GetCurrentMethod.Name() + " Exception: " + ex.Message)
                    End Try
                End Using
            End If
        End If
    End Sub
0 Likes
Accepted solutions (1)
3,759 Views
6 Replies
Replies (6)
Message 2 of 7

_gile
Consultant
Consultant

@SRSDS  a écrit :

Hi,

 

Can someone please try to spot what's wrong to get an eWasOpenForWrite on the line

 db.Clayer = acLyrTbl("DIM")

 

 Private Sub doc_CommandWillStart(ByVal sender As Object, ByVal e As CommandEventArgs)
        If PauseEvents = False Then
            If e.GlobalCommandName = "DIMLINEAR" Or e.GlobalCommandName = "DIMALIGNED" Or e.GlobalCommandName = "DIMANGULAR" Or e.GlobalCommandName = "DIMCONTINUE" Then
                Using trans As Transaction = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartOpenCloseTransaction : trcnt = trcnt + 1
                    Dim LayerName As String = "DIM"
                    Dim lyrId As ObjectId = Nothing
                    Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
                    Try
' here you open the layer table for read Dim lyrTbl As LayerTable = trans.GetObject(db.LayerTableId, OpenMode.ForRead, False) Using ltypTbl As LinetypeTable = trans.GetObject(db.LinetypeTableId, OpenMode.ForRead, False) Using myLayer As LayerTableRecord = New LayerTableRecord If lyrTbl.Has(LayerName) = False Then myLayer.Name = LayerName
' here you upgrade open the layer table (for write) lyrTbl.UpgradeOpen() lyrTbl.Add(myLayer) trans.AddNewlyCreatedDBObject(myLayer, True) End If lyrId = lyrTbl.Item(LayerName) End Using End Using
' here you open layer table again which is already opened for write Dim acLyrTbl As LayerTable = trans.GetObject(db.LayerTableId, OpenMode.ForRead) If acLyrTbl.Has("DIM") = True Then db.Clayer = acLyrTbl("DIM") End If trans.Commit() Catch ex As Exception MsgBox(Reflection.MethodBase.GetCurrentMethod.Name() + " Exception: " + ex.Message) End Try End Using End If End If End Sub

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 7

SRSDS
Advisor
Advisor

Hi Gile,

That second section of code was moved in from another subroutine to try to show the problem a little more simply.

Without changing the code what would I need to add to 'close' the layer table.

I've tried:

lyrTbl.DownradeOpen 

lyrTbl.Dispose 

but they don't work.

 

If I use StartTransaction instead of StartOpenCloseTransaction the problem goes away but it's in an event handler so I believe I need to use the latter.

 

0 Likes
Message 4 of 7

_gile
Consultant
Consultant

I'm not very comfortable with VB (actually, I hate VB) but try this 'corrected' code:

 

    Private Sub doc_CommandWillStart(ByVal sender As Object, ByVal e As CommandEventArgs)
        If Not PauseEvents Then 'Not booleanValue is clearer and less verbose than than booleanValue = False
            If e.GlobalCommandName = "DIMLINEAR" Or e.GlobalCommandName = "DIMALIGNED" Or e.GlobalCommandName = "DIMANGULAR" Or e.GlobalCommandName = "DIMCONTINUE" Then
                Using trans As Transaction = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartOpenCloseTransaction : trcnt = trcnt + 1
                    Dim LayerName As String = "DIM"
                    Dim lyrId As ObjectId = ObjectId.Null 'ObjectId type is a non nullable type
                    Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
                    Try
                        Dim lyrTbl As LayerTable = trans.GetObject(db.LayerTableId, OpenMode.ForRead) 'False arg is useless a table cannot be erased
                        If Not lyrTbl.Has(LayerName) Then
                            Using myLayer As LayerTableRecord = New LayerTableRecord
                                myLayer.Name = LayerName
                                lyrTbl.UpgradeOpen()
                                lyrTbl.Add(myLayer)
                                trans.AddNewlyCreatedDBObject(myLayer, True)
                                lyrId = lyrTbl.Item(LayerName)
                            End Using
                        End If
						'use the lyrTbl variable which already contains the current layer table
                        If lyrTbl.Has("DIM") Then 'lyrTbl.Has("DIM") = True is verbose, simply use: lyrTbl.Has("DIM") instead
                            db.Clayer = lyrTbl("DIM")
                        End If
                        trans.Commit() 
                    Catch ex As Exception
                        MsgBox(Reflection.MethodBase.GetCurrentMethod.Name() + " Exception: " + ex.Message)
                    End Try
                End Using
            End If
        End If
    End Sub


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 5 of 7

SRSDS
Advisor
Advisor

I shouldn't have tried to compact the code to explain the issue.

The problem I'm facing is that I have a one subroutine to add a new layer 

and another that sets the current layer.

 

After I add a new layer the layer table is left open; for write I guess and I can't close it.

 

And when I try to set the current layer using the SetCurrentLayer subroutine it creates the error:

 

    Public Sub SetCurrentLayer(ByVal sLayerName As String, ByRef trans As Transaction)
        Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
        Try
            Dim acLyrTbl As LayerTable = trans.GetObject(db.LayerTableId, OpenMode.ForRead)
            If acLyrTbl.Has(sLayerName) = True Then
                db.Clayer = acLyrTbl(sLayerName)
            End If
        Catch ex As Exception
            MsgBox(Reflection.MethodBase.GetCurrentMethod.Name() + " Exception: " + ex.Message)
        End Try
    End Sub

 

 

 

 

 

0 Likes
Message 6 of 7

_gile
Consultant
Consultant
Accepted solution

If you call two different method, it would be safer to use a different 'transaction' for each method.

        public ObjectId GetOrCreateLayer(Database db, string layerName)
        {
            ObjectId id;
            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var layerTable = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
                if (layerTable.Has(layerName))
                {
                    id = layerTable[layerName];
                }
                else
                {
                    layerTable.UpgradeOpen();
                    var layer = new LayerTableRecord();
                    layer.Name = layerName;
                    id = layerTable.Add(layer);
                    tr.AddNewlyCreatedDBObject(layer, true);
                }
                tr.Commit();
            }
            return id;
        }

        public bool TrySetCurrentLayer(Database db, string layerName)
        {
            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var layerTable = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
                if (layerTable.Has(layerName))
                {
                    db.Clayer = layerTable[layerName];
                    return true;
                }
            }
            return false;
        }

But, if I do not misunderstand, using the upper GetOrCreatelayer() method, you do not need the second method, you can simply do:

db.Clayer = GetOrCreatelayer(db, "DIM");

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 7 of 7

SRSDS
Advisor
Advisor

That clears things up and also given me several tips.

Thanks again.

0 Likes