Author Topic: create Layers, is there a better way  (Read 13420 times)

0 Members and 1 Guest are viewing this topic.

sinc

  • Guest
Re: create Layers, is there a better way
« Reply #15 on: January 03, 2008, 02:33:03 PM »
In my testing, LayerTable.Has() returns the correct result.  It's just that if you then do LayerTable[layerName], you may get an erased version of the layer, and trying to use that layer will cause you problems.

sinc

  • Guest
Re: create Layers, is there a better way
« Reply #16 on: January 03, 2008, 02:47:11 PM »
You'll notice the method has been decorated with the CommandMethod attribute, so this is the command definition. The return will just return out of this method/function and hand control back to AutoCAD.
COOL!! I learned something new today!!!  Dont read into this more than what Im saying, but its like an internal ESC key for the function.  Its there so quit the Command(CommandMethod).  VERY nice.  I love .Net

There is a school of thought that it is bad form to exit out of the middle of a method in this fashion.  There is a whole class of potential bugs that can created by doing that.

However, the alternative is usually to use a conditional statement, which adds a layer of braces, and makes the code a bit messier and harder to read.  A better solution also involves using a conditional statement, but then breaking the rest of the logic out into other methods.  Sometimes this provides a much-better and more-robust solution with more-generic applicability, but sometimes it's just more work for little gain.  So some people like to have the return in the middle of the method.

I tend to agree with the hardliners that it is "bad form" to return from the middle of a method, and usually try to return from the ends of methods.  But I'm not strict about it, and I occasionally return from the middle of a method, for one of the reasons I just mentioned.

CmdrDuh

  • Automatic Duh Generator
  • King Gator
  • Posts: 4039
Re: create Layers, is there a better way
« Reply #17 on: January 03, 2008, 02:50:04 PM »
One other thing: This is C#, so stop thinking of them as Sub's and forget that VB drivel  :evil:  :-D
Curly braces rule  :-D
So think of them as methods right?
Quote from: Glenn R
..get some code books did we
Kinda, I got a book at AU which I'm using/abusing to try and help me learn this stuff.  I am finding that while it does give me an example of "working" code, you guys are showing me better and faster ways of doing things.
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: create Layers, is there a better way
« Reply #18 on: January 03, 2008, 02:53:28 PM »
Methods or functions - I tend to think of them as functions, but that's just personal preference.
Glad you're liking it and getting into the 'heavier' end - you can definately do more with .NET.
Me

CmdrDuh

  • Automatic Duh Generator
  • King Gator
  • Posts: 4039
Re: create Layers, is there a better way
« Reply #19 on: January 03, 2008, 03:08:15 PM »
And while I'm asking tons of questions, why the AS ?
Code: [Select]
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead, false) as LayerTable;vs
Code: [Select]
LayerTable LT = (LayerTable)DB.LayerTableId.GetObject(Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite);
Is it b/c your using the .GetObject of the transaction instead of the database.layertableid.getobject?  I saw a thread on Through-the-Interface talking about the AS, but I didn't understand what they said.
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second

sinc

  • Guest
Re: create Layers, is there a better way
« Reply #20 on: January 03, 2008, 03:15:59 PM »

This line will throw an exception if objId is the id for something that is not a layer table:

Code: [Select]
LayerTable lt = (LayerTable)tr.GetObject(objId, OpenMode.ForRead, false);
This line will result in lt == null if objId is the id for something that is not a layer table:

Code: [Select]
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead, false) as LayerTable;

sinc

  • Guest
Re: create Layers, is there a better way
« Reply #21 on: January 03, 2008, 03:17:53 PM »
Methods or functions - I tend to think of them as functions, but that's just personal preference.
Glad you're liking it and getting into the 'heavier' end - you can definately do more with .NET.


Well, you might say Methods belong to an object, while Functions do not.

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: create Layers, is there a better way
« Reply #22 on: January 03, 2008, 03:39:08 PM »
And while I'm asking tons of questions, why the AS ?
Code: [Select]
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead, false) as LayerTable;vs
Code: [Select]
LayerTable LT = (LayerTable)DB.LayerTableId.GetObject(Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite);
Is it b/c your using the .GetObject of the transaction instead of the database.layertableid.getobject?  I saw a thread on Through-the-Interface talking about the AS, but I didn't understand what they said.

Well, there's IS and AS. Is will test if an object IS some type of object, whereas AS will try and cast some object to another object.

When you do this:
Code: [Select]
(LayerTable)DB.LayerTableId blah blah

you are actually doing what's called a direct cast - casting directly from the return type of DbObject, in this example, to a LayerTable.

When you use AS, it will do the cast for you and either return a valid object or null and, here's the most important bit, AS will not throw an exception whereas a direct cast will.

Also, I would recommend not using the GetObject() method off an ObjectId and use GetObject() off the transaction you've started because the intent will be much clearer, but that's just my opinion.

Cheers,
Glenn.
Me

CmdrDuh

  • Automatic Duh Generator
  • King Gator
  • Posts: 4039
Re: create Layers, is there a better way
« Reply #23 on: January 03, 2008, 03:50:52 PM »
Quote from: Glenn R
Well, there's IS and AS. Is will test if an object IS some type of object, whereas AS will try and cast some object to another object.
When you do this:
Code: [Select]
(LayerTable)DB.LayerTableId blah blah

you are actually doing what's called a direct cast - casting directly from the return type of DbObject, in this example, to a LayerTable.
OK, good, I knew I was casting.  I didn't know this was "direct" cast which could fail.
Quote from: Glenn R
When you use AS, it will do the cast for you and either return a valid object or null and, here's the most important bit, AS will not throw an exception whereas a direct cast will.
So we need to test for Null?  How else would we know it worked?
Quote from: Glenn R
Also, I would recommend not using the GetObject() method off an ObjectId and use GetObject() off the transaction you've started because the intent will be much clearer, but that's just my opinion.

Cheers,
Glenn.
Noted, and appreciated!  I have a hard enough time reading my own drivel, let alone someone else trying to figure out what Im thinking.  On a side note, I had someone call me and ask what 'Spit the Dummy' meant b/c it popped up on their screen one day
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: create Layers, is there a better way
« Reply #24 on: January 03, 2008, 03:56:56 PM »
So we need to test for Null?  How else would we know it worked?

That's exactly right. So, revising what I posted earlier in this thread, you would do this:
Code: [Select]
[CommandMethod("CreateDuhLayer")]
static public void createduhlayer()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

using (Transaction tr = db.TransactionManager.StartTransaction()) {
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead, false) as LayerTable;
if (lt == null)
return;
if (lt.Has("Some LayerNameGoesHere"))
return;

LayerTableRecord newLTR = new LayerTableRecord();
newLTR.Name = "SomeLayerNameGoesHere";
// set any other properties

lt.UpgradeOpen();
lt.Add(newLTR);

tr.AddNewlyCreatedDBObject(newLTR, true);

tr.Commit();
}

}

Cheers,
Glenn.
Me

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: create Layers, is there a better way
« Reply #25 on: January 03, 2008, 03:58:30 PM »
On a side note, I had someone call me and ask what 'Spit the Dummy' meant b/c it popped up on their screen one day

 :lmao:
Me

CmdrDuh

  • Automatic Duh Generator
  • King Gator
  • Posts: 4039
Re: create Layers, is there a better way
« Reply #26 on: January 03, 2008, 04:37:02 PM »
One last question and I'll stop beating this dead horse for today.  If in the new version you posted, if the return; is called, the transaction is aborted/disposed of properly because the function loses scope?  Should we use tr.Abort() or not, and if not, when would we use tr.Abort()  ?
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second

BeanBag

  • Guest
Re: create Layers, is there a better way
« Reply #27 on: January 03, 2008, 06:54:44 PM »
I found this thread on direct casting from Through the Interface:

http://through-the-interface.typepad.com/through_the_interface/2006/09/working_with_sp.html

Some thoughts from the Autodesk labs. All the code below is taken from Lab 5.

Direct casting is used through out for layertable, blocktable and blocktablerecord in the Labs. With these is there ever a chance it could not return these objects?

In the labs direct casting is used with try catch statements where the exception is used in similar way to if-else statement.

They use entity within a block here:

Code: [Select]
Entity ent = (Entity)trans.GetObject(id, OpenMode.ForRead, false);
                    if (ent is AttributeDefinition)

Below code is called on items selected by the user: Is Gettype() and typeof() interchangeable with IS  as shown above?

Code: [Select]
Entity ent = (Entity)trans.GetObject(employeeId, OpenMode.ForRead, false); // Use it to open the current object!
                if (ent.GetType() == typeof(BlockReference)) // We use .NET's RTTI to establish type.


This is their layer create:

Code: [Select]
private ObjectId CreateLayer()
        {
            ObjectId layerId;
            Database db = HostApplicationServices.WorkingDatabase;

            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                //Get the layer table first...
                LayerTable lt = (LayerTable)trans.GetObject(db.LayerTableId, OpenMode.ForRead);
                //Check if EmployeeLayer exists...
                if (lt.Has("EmployeeLayer"))
                {
                    layerId = lt["EmployeeLayer"];
                }
                else
                {
                    //If not, create the layer here.
                    LayerTableRecord ltr = new LayerTableRecord();
                    ltr.Name = "EmployeeLayer"; // Set the layer name
                    ltr.Color = Color.FromColorIndex(ColorMethod.ByAci, 2);
                    // upgrade the open from read to write
                    lt.UpgradeOpen();
                    layerId = lt.Add(ltr);
                    trans.AddNewlyCreatedDBObject(ltr, true);
                }
                trans.Commit();
            }
            return layerId;
        }


******************EDIT***********************
I thought I would run a test on Lab 5
Ran the command and then purged and then ran command again  :evil:

It threw an exception here:

Code: [Select]
BlockTableRecord empBtr = (BlockTableRecord)trans.GetObject(bt["EmployeeBlock"], OpenMode.ForRead);
It detected that the block and layer had been deleted and created them again so not sure what is happening here.
« Last Edit: January 03, 2008, 08:12:54 PM by BeanBag »

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: create Layers, is there a better way
« Reply #28 on: January 03, 2008, 07:39:58 PM »
One last question and I'll stop beating this dead horse for today.  If in the new version you posted, if the return; is called, the transaction is aborted/disposed of properly because the function loses scope?  Should we use tr.Abort() or not, and if not, when would we use tr.Abort()  ?

Well, strictly speaking, the 'using' scope is exited first and that in turn calls Dispose() on whatever was being 'used'...in this case, a transaction. Now, if Dispose() is called on a transaction and it hasn't been commited, then an implicit Abort() is called on the transaction and then it's memory is cleaned up.

Then of course it bails out of the function.

Cheers,
Glenn.
Me

BeanBag

  • Guest
Re: create Layers, is there a better way
« Reply #29 on: January 03, 2008, 08:20:33 PM »
I've been able to fix lab 5 by adding true on the end - letting it open deleted objects:

Code: [Select]
BlockTableRecord empBtr = (BlockTableRecord)trans.GetObject(bt["EmployeeBlock"], OpenMode.ForRead, true);
I find this strange - the block and layer are created and trans.commit() is called.  :|  Its a nested transaction though.

My guess here is that since the block and layer are created with in a nested transaction the database has not been updated and still registers it deleted until the very final trans.commit() is called? Nope I denested them and same problem but at least now the layer and block appear in drawing even though it throws the exception.

THis is probably a better fix - use the objectID instead of block name - it works to and don't need to let it use deleted objects:

Code: [Select]
BlockTableRecord empBtr = (BlockTableRecord)trans.GetObject(blockId, OpenMode.ForRead);
LOL well after all that you can purge layers/blocks and layertable.has("layername") and blocktable.has("blockname") will work to say they don't exisit

But don't use block names to get the block from blocktable because even if you create it again after purging it still says its erased until you open and close drawing. Weird.
« Last Edit: January 03, 2008, 08:44:20 PM by BeanBag »