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
Solved! Go to Solution.
Solved by _gile. Go to Solution.
@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
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.
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
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
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");
Can't find what you're looking for? Ask the community or share your knowledge.