Author Topic: Check for layer, make it current. What's wrong in my code?  (Read 4529 times)

0 Members and 1 Guest are viewing this topic.

gablackburn

  • Guest
Check for layer, make it current. What's wrong in my code?
« on: June 20, 2012, 02:57:26 PM »
In the code posted below, I've created a sub-routine where I'm checking to see if my WALLS layer is present.  If it isn't present, it's created.  If it is, I thaw, unlock and turn it on.  At the end, I make it the current layer.

The problem I'm running into is someone else's code which is crashing out with an eInvalidLayer error if it's run immediately after my code is run.

I want to make sure my code is solid, is it possible to see if anyone finds any problems with what I'm doing.

Caution, I still consider myself a n00b so go easy.

Code - vb.net: [Select]
  1.  
  2. Private Sub CheckWALLSLayer()
  3.         Dim myTransMan As DatabaseServices.TransactionManager
  4.         Dim myDwg As Document
  5.         Dim myLT As LayerTable
  6.         Dim myLTR As LayerTableRecord
  7.         Try
  8.             myDwg = Application.DocumentManager.MdiActiveDocument
  9.             myTransMan = myDwg.TransactionManager
  10.             Using myTrans As DatabaseServices.Transaction = myTransMan.StartTransaction
  11.                 myLT = myDwg.Database.LayerTableId.GetObject(OpenMode.ForRead)
  12.                 Dim myWALLS As String = "WALLS"
  13.  
  14.                 'CHECK FOR THE LAYER BEFORE YOU BEGIN
  15.                 If myLT.Has(myWALLS) = False Then
  16.                     myLTR = New LayerTableRecord
  17.                     myLTR.Name = myWALLS
  18.                     myLTR.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, 6) 'MAGENTA
  19.                     myLT.UpgradeOpen()
  20.                     myLT.Add(myLTR)
  21.                     myTrans.AddNewlyCreatedDBObject(myLTR, True)
  22.                 Else
  23.                     myLTR = myTransMan.GetObject(myLT(myWALLS), OpenMode.ForWrite)
  24.                     With myLTR
  25.                         If .IsOff Then .IsOff = False
  26.                         If .IsFrozen Then .IsFrozen = False
  27.                         If .IsLocked Then .IsLocked = False
  28.                     End With
  29.                 End If
  30.  
  31.                 'TURN ON THE LAYERTABLE FOR WRITE
  32.                 myTrans.Commit()
  33.             End Using
  34.            
  35.             'MAKE SURE WALLS LAYER IS CURRENT
  36.             ApplicationServices.Application.SetSystemVariable("CLAYER", "WALLS")
  37.  
  38.         Catch ex As Autodesk.AutoCAD.Runtime.Exception
  39.             MsgBox("Error during WALLS Layer setup - " & Err.ToString)
  40.         Finally
  41.          End Try
  42.     End Sub
  43.  

Thanks in advance,

G.A. Blackburn

edit:kdub->code formatting code=vbnet
« Last Edit: June 20, 2012, 10:06:30 PM by Kerry »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Check for layer, make it current. What's wrong in my code?
« Reply #1 on: June 20, 2012, 07:13:06 PM »
Quote
The problem I'm running into is someone else's code which is crashing out with an eInvalidLayer error if it's run immediately after my code is run.

clarify immediately ?

I can't see anything that would cause an error.

Re your code.
Personally I'd make a generic routine and pass parameters to it  ie : AssertMyLayers ( layerName, layerColor, layerLineType)
 ... This will save you reproducing this routine for each layer you want.

You don't need myTransMan .. you can do everything from the Transaction.

You make a string variable myWALLS to hold the layerName, yet you use a fixed string to set the SystemVariable.

If you want the layer ON and UNFROZEN and UNLOCKED just set them that way, no need to test current property.
 
You could use
db.Clayer = myLT[myWALLS]; <== sorry, I think in C#
in place of the Set SystemVariable call.


Regards
kdub
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

trembre

  • Guest
Re: Check for layer, make it current. What's wrong in my code?
« Reply #2 on: June 20, 2012, 07:32:17 PM »
 Should your initial myLT definition be OpenMode.ForWrite?  If the layer doesn't exist, you add it to the LayerTable although it has been opened ForRead.  No idea if the UpgradeOpen would supercede that.

 Further to that, you should probably dispose of the myLT instance after your If statement too.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Check for layer, make it current. What's wrong in my code?
« Reply #3 on: June 20, 2012, 10:50:32 PM »
Perhaps something like this would suit you.
Converting from C# should not be a problem

Code - C#: [Select]
  1.         //=======================================================================
  2.         [CommandMethod("TL01")]
  3.         public void TestLayer01()
  4.         {
  5.             ObjectId  layerID6 = CreateLayer(db, "WALLS", 6);
  6.  
  7.             ObjectId  layerID5 = CreateLayer(db, "DOORS", 5);
  8.  
  9.             /// assume the layerID's will be use later: perhaps could make a property accessor , if not no matter.
  10.         }
  11.  
  12.         public static ObjectId CreateLayer(Database db, string layerName, short color)
  13.         {
  14.             ObjectId layerId;
  15.             using (Transaction tr = db.TransactionManager.StartTransaction())
  16.             {
  17.                 var lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForWrite);
  18.                 //Check if Layer exists...
  19.                 if (lt.Has(layerName))
  20.                 {
  21.                     var ltr = (LayerTableRecord)tr.GetObject(lt[layerName], OpenMode.ForWrite);
  22.                     ltr.IsOff = false;
  23.                     ltr.IsFrozen = false;
  24.                     ltr.IsLocked = false;
  25.                     layerId = ltr.ObjectId;
  26.                 }
  27.                 else
  28.                 {
  29.                     //if not, create the layer here.
  30.                     var ltr = new LayerTableRecord { Name = layerName, Color = Color.FromColorIndex(ColorMethod.ByAci, color) };
  31.                     layerId = lt.Add(ltr);
  32.                     tr.AddNewlyCreatedDBObject(ltr, true);
  33.                 }
  34.                 tr.Commit();
  35.             }
  36.             return layerId;
  37.         }
  38.  

added:
In this case the db value is set from a property accessor
The value is equivalent to
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;

Regards
kdub
« Last Edit: June 20, 2012, 10:55:19 PM by Kerry »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Check for layer, make it current. What's wrong in my code?
« Reply #4 on: June 21, 2012, 12:25:03 AM »

Then to make a layer current , simply something like

Code - C#: [Select]
  1.    
  2.      
  3.         db.Clayer = layerID5;
  4.  
  5.  
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

gablackburn

  • Guest
Re: Check for layer, make it current. What's wrong in my code?
« Reply #5 on: June 21, 2012, 08:33:23 AM »
Thanks Kerry & trembre for the responses. 

It turns out the problem was with the other developer's code all along as his code was crashing out if the command started up in the WALLS layer.  I now switch my current layer to the WALLS2 layer if I know his code will be run and everything is copacetic.  I didn't think it was on his end as he's a much more experienced developer and I just assumed something was wrong with my code.

I actually changed the code so that I'm passing the layer name when calling the routine (thanks Kerry) and I'll look into a couple of the other suggestions too.

Much appreciated everyone and thanks for not going Tony Tanzillo on my ass.  :)

GAB


trembre

  • Guest
Re: Check for layer, make it current. What's wrong in my code?
« Reply #6 on: June 21, 2012, 06:37:34 PM »
That still does sound a little strange though - the switching to the WALLS2 layer to stop the crashing may only be working around the problem, as opposed to fixing it?  That kind of thing would bug me - I'd be waiting for whatever it was doing wrong to pop up and bite me somewhere else. 

I think Tony's pre-Swamp reputation is much worse than how he's actually been posting since he started here - even when he has fired up a little, it's still a learning experience as I hadn't previously given much thought to extension methods or the nuts and bolts of updating my code beyond AutoCAD 2012.  I'm now adding extension methods to my own AutoCAD utilities class I've been putting together down the years - it's pretty cool stuff!

gablackburn

  • Guest
Re: Check for layer, make it current. What's wrong in my code?
« Reply #7 on: June 26, 2012, 06:07:57 PM »
trembre, the other developer no longer works with us, so my powers-that-be want me to redo his code.  Turns out it won't be biting me in the ass later on.  :)

< .. >

Thanks again.


edit:kdub
« Last Edit: June 26, 2012, 06:21:53 PM by Kerry »

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: Check for layer, make it current. What's wrong in my code?
« Reply #8 on: July 06, 2017, 02:59:59 AM »
Just ran through a similar problem with my code and google brought me here. After some troubleshooting, it looks like CAD is throwing the error because the current layer is being thawed, maybe .IsFrozen is readonly on the current layer. I'm posting my findings for any other lost souls who end up here.

Busted Code:
Code - C#: [Select]
  1. [CommandMethod("LayerTest")]
  2. public static void LayerTest()
  3. {
  4.   // get the current layer
  5.   string layerName = (string) Application.GetSystemVariable("CLAYER");
  6.   using (Transaction tr = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction())
  7.   {
  8.     LayerTable layerTable = (LayerTable)tr.GetObject(Active.Database.LayerTableId, OpenMode.ForWrite);
  9.     if (layerTable.Has(layerName))
  10.     {
  11.       LayerTableRecord currentLayer = tr.GetObject(layerTable[layerName], OpenMode.ForWrite) as LayerTableRecord;
  12.       // now try to thaw it.
  13.       if (currentLayer != null)
  14.       {
  15.         currentLayer.IsFrozen = false; //<-eInvalidLayer error here. There is no error if the layer being thawed isn't current
  16.       }
  17.     }
  18.     tr.Commit();
  19.   }
  20. }
  21.  

My solution was to check that the layer was frozen before trying to thaw it.
« Last Edit: July 06, 2017, 12:27:00 PM by Atook »

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: Check for layer, make it current. What's wrong in my code?
« Reply #9 on: July 06, 2017, 06:01:04 AM »
Also check if a layer is deleted during the session. Checking the database returns the layer as if it is still there.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.