Author Topic: Get the current layout  (Read 1508 times)

0 Members and 1 Guest are viewing this topic.

Offline rom1

  • Visual Basic
  • *
  • Posts: 21
  • Karma: +3/-0
  • Gender: Male
    • prefered language: VB
    • Prog expertise: Good
    • View Profile
Get the current layout
« on: November 23, 2010, 07:45:21 AM »
Hi,

Here is a sample function in order to get back the current layout:

Code: [Select]

    Function F_GetCurrentLayout() As Layout
        ' Get the current document and database, and start a transaction '
        Dim acCurDb As Database = AcadAp.DocumentManager.MdiActiveDocument.Database
        Dim acLayoutMgr As LayoutManager
        Dim acLayout As Layout = Nothing

        Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
            Try
                acLayoutMgr = LayoutManager.Current ' Reference the Layout Manager
                ' Get the current layout
                acLayout = acTrans.GetObject(acLayoutMgr.GetLayoutId(acLayoutMgr.CurrentLayout), OpenMode.ForRead)

            Catch ex As Exception
                Dim Msg As String = "Error in function F_GetCurrentLayout"
                Dim Titre As String = "Operation cancelled"
                MessageBox.Show(Msg, Titre, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1)
                acTrans.Abort()

            Finally
                ' Close transaction '
                acTrans.Dispose()
            End Try
        End Using

        Return acLayout
    End Function

Thanks for your remarks.


target audience:{intermediate}

Offline Jeff H

  • Newbie
  • *
  • Posts: 10
  • Karma: +3/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Beginner
    • View Profile
Re: Get the current layout
« Reply #1 on: November 24, 2010, 04:44:22 AM »
It is quicker to call Transaction.Commit and if you have an error you are calling Abort and Dispose on the transaction.
Another thing to consider is nested transactions when you commit a transaction that is nested it passes up the objects to the containing transaction, but in with the finally statement it will be disposed.
You can also find your answers @TheSwamp

Offline rom1

  • Visual Basic
  • *
  • Posts: 21
  • Karma: +3/-0
  • Gender: Male
    • prefered language: VB
    • Prog expertise: Good
    • View Profile
Re: Get the current layout
« Reply #2 on: November 24, 2010, 08:20:38 AM »

Hi Jeff H,

- Do you mean that i should use 'acTrans.Commit' instead of 'acTrans.Dispose' in the 'Finally' statement?

- Sorry, but i don't really understand your explanation of nested transaction... You mean for example that if a call the 'GetCurrentLayout' function from another function in which a transaction is started, i don't need to dispose the transaction in 'GetCurrentLayout' if the transaction is disposed in the calling function?

Thanks.

Offline Jeff H

  • Newbie
  • *
  • Posts: 10
  • Karma: +3/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Beginner
    • View Profile
Re: Get the current layout
« Reply #3 on: November 24, 2010, 03:11:11 PM »
I would get Gile's input also, but I would dispose the transaction in the catch block and commit the after End Try.
So if you have an error you dispose if not you commit.
And not worry about the finally block.

I am about to run out to the field, so later today or this weekend I will double check this but,
If you use Transaction.GetObject then try to pass to the caller which is inside a transaction you might get an error. Do not quote me on that I on going off of memory
You can also find your answers @TheSwamp

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Get the current layout
« Reply #4 on: November 24, 2010, 05:16:16 PM »
As far as I know, while using a 'Using' statement on an object, you don't need to explicitly call dispose. The object should be automatically disposed at the end of the code block  or if an exception is thrown.

With a transaction, all the objects opened with Transaction.GetObject() and the new ones added to the transaction with AddNewlyCreatedDBObject() should be automatically disposed too.
But if an error occurs before 'new' objects are added to the database, they won't be disposed.

If an exception occurs before the transactions is committed, the Dispose() is called by 'Using' and all changes made to database within this transaction are rolled back.

So, in my opinion, the F_GetCurrentLayout method should be like this (no need to Commit the transaction while there were no changes to the Database):
Code: [Select]
Public Function F_GetCurrentLayout() As Layout
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim lm As LayoutManager = LayoutManager.Current
Using tr As Transaction = db.TransactionManager.StartTransaction()
Return DirectCast(tr.GetObject(lm.GetLayoutId(lm.CurrentLayout), OpenMode.ForRead), Layout)
End Using
End Function

To learn more about when and what disposing, you can have a look to this video

Offline Kerry

  • C#
  • *
  • Posts: 6
  • Karma: +2/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Good
    • View Profile
Re: Get the current layout
« Reply #5 on: November 27, 2010, 02:54:56 AM »
Greetings Gentlemen.

The transaction IS Disposed automatically when contained in a using statement.

For example, the following c# code when viewed as IL code (Intermediate Language as Compiled) shows the dispose statement.

Code: [Select]
[CommandMethod("DrawALine")]
public static void DrawALine()
{
    Database db = Application.DocumentManager.MdiActiveDocument.Database;
    Point3d startPoint = new Point3d(0.0, 0.0, 0.0);
    Point3d endPoint = new Point3d(10.0, 20.0, 30.0);
    Line myLine = new Line(startPoint, endPoint);
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
        (tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord).AppendEntity(myLine);
        tr.AddNewlyCreatedDBObject(myLine, true);
        tr.Commit();
    }
}

Code: [Select]
method public hidebysig static void DrawALine() cil managed
{
    .custom instance void [acmgd]Autodesk.AutoCAD.Runtime.CommandMethodAttribute::.ctor(string) = { string('DrawALine') }
    .maxstack 4
    .locals init (
        [0] class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Database db,
        [1] valuetype [acdbmgd]Autodesk.AutoCAD.Geometry.Point3d startPoint,
        [2] valuetype [acdbmgd]Autodesk.AutoCAD.Geometry.Point3d endPoint,
        [3] class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Line myLine,
        [4] class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Transaction tr,
        [5] class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.BlockTable bt,
        [6] class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.BlockTableRecord btrMS,
        [7] bool CS$4$0000)
    L_0000: nop
    L_0001: call class [acmgd]Autodesk.AutoCAD.ApplicationServices.DocumentCollection [acmgd]Autodesk.AutoCAD.ApplicationServices.Application::get_DocumentManager()
    L_0006: callvirt instance class [acmgd]Autodesk.AutoCAD.ApplicationServices.Document [acmgd]Autodesk.AutoCAD.ApplicationServices.DocumentCollection::get_MdiActiveDocument()
    L_000b: callvirt instance class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Database [acmgd]Autodesk.AutoCAD.ApplicationServices.Document::get_Database()
    L_0010: stloc.0
    L_0011: ldloca.s startPoint
    L_0013: ldc.r8 0
    L_001c: ldc.r8 0
    L_0025: ldc.r8 0
    L_002e: call instance void [acdbmgd]Autodesk.AutoCAD.Geometry.Point3d::.ctor(float64, float64, float64)
    L_0033: nop
    L_0034: ldloca.s endPoint
    L_0036: ldc.r8 10
    L_003f: ldc.r8 20
    L_0048: ldc.r8 30    L_0051: call instance void [acdbmgd]Autodesk.AutoCAD.Geometry.Point3d::.ctor(float64, float64, float64)
    L_0056: nop
    L_0057: ldloc.1
    L_0058: ldloc.2
    L_0059: newobj instance void [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Line::.ctor(valuetype [acdbmgd]Autodesk.AutoCAD.Geometry.Point3d, valuetype [acdbmgd]Autodesk.AutoCAD.Geometry.Point3d)
    L_005e: stloc.3
    L_005f: ldloc.0
    L_0060: callvirt instance class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.TransactionManager [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Database::get_TransactionManager()
    L_0065: callvirt instance class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Transaction [acdbmgd]Autodesk.AutoCAD.DatabaseServices.TransactionManager::StartTransaction()
    L_006a: stloc.s tr
    L_006c: nop
    L_006d: ldloc.s tr
    L_006f: ldloc.0
    L_0070: callvirt instance valuetype [acdbmgd]Autodesk.AutoCAD.DatabaseServices.ObjectId [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Database::get_BlockTableId()
    L_0075: ldc.i4.0
    L_0076: callvirt instance class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.DBObject [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Transaction::GetObject(valuetype [acdbmgd]Autodesk.AutoCAD.DatabaseServices.ObjectId, valuetype [acdbmgd]Autodesk.AutoCAD.DatabaseServices.OpenMode)
    L_007b: isinst [acdbmgd]Autodesk.AutoCAD.DatabaseServices.BlockTable
    L_0080: stloc.s bt
    L_0082: ldloc.s tr
    L_0084: ldloc.s bt
    L_0086: ldsfld string modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst) [acdbmgd]Autodesk.AutoCAD.DatabaseServices.BlockTableRecord::ModelSpace
    L_008b: callvirt instance valuetype [acdbmgd]Autodesk.AutoCAD.DatabaseServices.ObjectId [acdbmgd]Autodesk.AutoCAD.DatabaseServices.SymbolTable::get_Item(string)
    L_0090: ldc.i4.1
    L_0091: callvirt instance class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.DBObject [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Transaction::GetObject(valuetype [acdbmgd]Autodesk.AutoCAD.DatabaseServices.ObjectId, valuetype [acdbmgd]Autodesk.AutoCAD.DatabaseServices.OpenMode)
    L_0096: isinst [acdbmgd]Autodesk.AutoCAD.DatabaseServices.BlockTableRecord
    L_009b: stloc.s btrMS
    L_009d: ldloc.s btrMS
    L_009f: ldloc.3
    L_00a0: callvirt instance valuetype [acdbmgd]Autodesk.AutoCAD.DatabaseServices.ObjectId [acdbmgd]Autodesk.AutoCAD.DatabaseServices.BlockTableRecord::AppendEntity(class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Entity)
    L_00a5: pop
    L_00a6: ldloc.s tr
    L_00a8: ldloc.3
    L_00a9: ldc.i4.1
    L_00aa: callvirt instance void [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Transaction::AddNewlyCreatedDBObject(class [acdbmgd]Autodesk.AutoCAD.DatabaseServices.DBObject, bool)
    L_00af: nop
    L_00b0: ldloc.s tr
    L_00b2: callvirt instance void [acdbmgd]Autodesk.AutoCAD.DatabaseServices.Transaction::Commit()
    L_00b7: nop
    L_00b8: nop
    L_00b9: leave.s L_00cf
    L_00bb: ldloc.s tr
    L_00bd: ldnull
    L_00be: ceq
    L_00c0: stloc.s CS$4$0000
    L_00c2: ldloc.s CS$4$0000
    L_00c4: brtrue.s L_00ce
    L_00c6: ldloc.s tr
    L_00c8: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    L_00cd: nop
    L_00ce: endfinally
    L_00cf: nop
    L_00d0: ret
    .try L_006c to L_00bb finally handler L_00bb to L_00cf
}

The transaction is disposed here   
L_00c6: ldloc.s tr   
L_00c8: callvirt instance void [mscorlib]System.IDisposable::Dispose()
L_00cd: nop
« Last Edit: November 27, 2010, 05:30:54 AM by Kerry Brown »
class keyThumper<T> : Lazy<T>

Offline Patriiick

  • Administrator
  • *****
  • Posts: 130
  • Karma: +1/-0
  • Gender: Male
    • prefered language: VB
    • Prog expertise: Good
    • View Profile
  • Twitter: @Patriiick
Re: Get the current layout
« Reply #6 on: November 27, 2010, 09:13:33 AM »
Interesting. I did not know IL code could be read, how do you do that?  :pasmal:


target audience:{intermediate}

Offline Kerry

  • C#
  • *
  • Posts: 6
  • Karma: +2/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Good
    • View Profile
Re: Get the current layout
« Reply #7 on: November 27, 2010, 10:18:35 AM »
Interesting. I did not know IL code could be read, how do you do that?  :pasmal:


target audience:{intermediate}

Hello Patrick,
 
2 ways

either with ILDASM.exe  http://msdn.microsoft.com/en-us/library/f7dy01k1(v=VS.100).aspx
or with .NET Reflector http://www.red-gate.com/products/reflector/index.htm

The .net Reflector may be better as you can view a DLL as  C#, VB, C++, F#, .... quite handy some times.

class keyThumper<T> : Lazy<T>