• Industries
  • Products
  • Buy
  • Services & Support
  • Communities
  • Discussion Groups

    .NET

    Reply
    Contributor
    Posts: 17
    Registered: ‎09-30-2007

    How to handle multiple open documents gracefully

    297 Views, 14 Replies
    10-02-2007 08:20 PM
    I have a .NET app that is loaded with the NETLOAD command. I have a single command method that loads a custom control into a palette, and displays it. Whenever my code needs a reference to "ThisDrawing", "ThisAcad", "ThisDB" etc... it is gotten from a function that returns the needed reference. That said I have a few questions:

    Why do my event handlers (the app in general) only become active after I type the command for my command method? Why are they not functional after the NETLOAD command? Is my application object (the class that contains my command method and my withevents member declarations) only instantiated when a command method is called?

    Why does my app stop working when a new drawing is opened if the AcadApp, Document, Editor, Database etc.. references are gotten from a function? Example:

    Dim WithEvents ThisDrawing as Document = GetDoc()

    I think I am incorrectly assuming that each time my code uses ThisDrawing, it's the same as calling GetDoc(). Maybe I should explicitly set ThisDrawing = GetDoc() each time a new drawing becomes active?

    Any other tips on gracefully handling the transition from active document to active document will be much appreciated as well.

    TIA
    Please use plain text.
    Valued Contributor
    Posts: 67
    Registered: ‎09-12-2006

    Re: How to handle multiple open documents gracefully

    10-03-2007 01:57 AM in reply to: jspark
    Concerning the event handlers, these must be initialized in the entrypoint of your app, not in the command method. The command method runs only when you call the corresponding command. The entrypoint runs when your app is loaded. That is the only thing that runs when an app is loaded.
    Please use plain text.
    *Tony Tanzillo

    Re: How to handle multiple open documents gracefully

    10-03-2007 06:27 AM in reply to: jspark
    I suppose that if you've been using VBA and its
    'ThisDrawing' object, you might become confused
    by what you take for granted.

    In VBA, 'ThisDrawing' looks like a variable, but is
    in reality, more like a function that always returns
    the Active document in the editor.

    So in .NET, rather than assigning a variable to
    the result of your GetDoc() function (which I
    presume returns the active document), you must
    call the GetDoc() function when want the Active
    document (or to make it easier, you can add a
    property to your class called 'ThisDrawing', and
    in the 'getter' for it, just return the active doc).

    When you're working with palettes, you should
    never cache a document object in a variable. You
    should always reference the MdiActiveDocument
    property of the DocumentCollection directly, when
    an operation begins, and then use that value only
    for the duration of the operation. An 'operation'
    means when the user clicks a button on your
    user interface, and in response, you access the
    active document to do something.

    What is also not obvious about VBA's 'ThisDrawing',
    is that when you handle an event of 'ThisDrawing',
    the event is fired for every open document, not
    just the one that was active when the event was
    assigned.

    In .NET, things are not as simple or automatic as
    they are in VBA.

    In .NET a Document object represents a single
    Document open in the editor, that has its own
    events. When you add a handler for a Document
    event to a Document, the handler only receives
    notification for the event in the Document that
    you added the handler to. So, to handle the same
    document event in every document, you must
    add the handler for the event to every document
    manually.

    In order to do that, you handle the events of the
    DocumentCollection (Application.DocumentManager),
    like DocumentAdded, and DocumentToBeDestroyed,
    and in the handlers for those events, you must add
    or remove your document event handlers to the
    newly added, or about-to-be closed document.

    If your app is not loaded at startup, then you also
    have to iterate over the collection of currently open
    documents, and add document events handlers to
    each of them.

    There's sample code showing how to do this on my
    website, but its in C#. There may be someone here
    that has converted it to VB.NET.


    --
    http://www.caddzone.com

    AcadXTabs: MDI Document Tabs for AutoCAD 2008
    Supporting AutoCAD 2000 through 2008
    http://www.acadxtabs.com

    wrote in message news:5738738@discussion.autodesk.com...
    I have a .NET app that is loaded with the NETLOAD command. I have a single command method that loads a custom control into a palette, and displays it. Whenever my code needs a reference to "ThisDrawing", "ThisAcad", "ThisDB" etc... it is gotten from a function that returns the needed reference. That said I have a few questions:

    Why do my event handlers (the app in general) only become active after I type the command for my command method? Why are they not functional after the NETLOAD command? Is my application object (the class that contains my command method and my withevents member declarations) only instantiated when a command method is called?

    Why does my app stop working when a new drawing is opened if the AcadApp, Document, Editor, Database etc.. references are gotten from a function? Example:

    Dim WithEvents ThisDrawing as Document = GetDoc()

    I think I am incorrectly assuming that each time my code uses ThisDrawing, it's the same as calling GetDoc(). Maybe I should explicitly set ThisDrawing = GetDoc() each time a new drawing becomes active?

    Any other tips on gracefully handling the transition from active document to active document will be much appreciated as well.

    TIA
    Please use plain text.
    Contributor
    Posts: 17
    Registered: ‎09-30-2007

    Re: How to handle multiple open documents gracefully

    10-03-2007 07:37 AM in reply to: jspark
    Thank you both for your time. It has been very enlightening. A few more questions with some sample code this time…

    In a nutshell, this is “MyApp” object:

    Imports Autodesk.AutoCAD.ApplicationServices
    Imports Autodesk.AutoCAD.Interop

    Public Class MyApp

    ‘Private Members
    Private WithEvents mThisAcad as AcadApplication = Ctype(ThisAcad.AcadApplication, AcadApplication)
    Private WithEvents mThisDrawing as AcadDocument = Ctype(ThisDrawing.AcadDocument, AcadDocument)

    ‘Public Properties
    Public Shared ReadOnly Property ThisAcad as Application
    Get
    Return Application.AcadApplication
    End Get
    End Property

    Public Shared ReadOnly Property ThisDrawing as Document
    Get
    Return Application.DocumentManager.MdiActiveDocument
    End Get
    End Property

    ‘Methods
    (Autodesk.AutoCAD.Runtime.CommandMethod("Start", "Start", _ Autodesk.AutoCAD.Runtime.CommandFlags.Modal)> _
    Public Sub Start()
    ‘Create a new PaletteSet and a Palette. Add Palette to PaletteSet.
    ‘Set PaletteSet.Visible = True
    EndSub

    ‘Events
    Private Sub mThisDrawing_ObjectAdded(ByVal Obj As Object) Handles _ mThisDrawing.ObjectAdded
    ‘Do Stuff
    End Sub

    End Class

    If I were to reset mThisDrawing = Ctype(ThisDrawing.AcadDocument, AcadDocument) each time a new Document becomes the active document, would my ObjectAdded event now only apply to the new active document?

    IIRC, my ObjectAdded event will not fire until my command method has been executed from the command prompt. Why is that? It's almost as if "MyApp" is not created until the command method is executed.

    I want “MyApp” object to be a single instance. Should I declare it as: Public Shared Class Myapp?

    Overall, I want a single MyApp object and a single PaletteSet object to handle any active document the user throws at it. What should I be (not be) doing to make this so? (I should probably not be declaring a NEW PaletteSet in my command method.)
    Please use plain text.
    *Tony Tanzillo

    Re: How to handle multiple open documents gracefully

    10-03-2007 08:44 AM in reply to: jspark
    In order for your event handler to be fired,
    there needs to be an instance of the class
    the handler is declared in.

    Have you wondered how an instance of your
    class is being created?

    --
    http://www.caddzone.com

    AcadXTabs: MDI Document Tabs for AutoCAD 2008
    Supporting AutoCAD 2000 through 2008
    http://www.acadxtabs.com

    wrote in message news:5739156@discussion.autodesk.com...
    Thank you both for your time. It has been very enlightening. A few more questions with some sample code this time…

    In a nutshell, this is “MyApp” object:

    Imports Autodesk.AutoCAD.ApplicationServices
    Imports Autodesk.AutoCAD.Interop

    Public Class MyApp

    ‘Private Members
    Private WithEvents mThisAcad as AcadApplication = Ctype(ThisAcad.AcadApplication, AcadApplication)
    Private WithEvents mThisDrawing as AcadDocument = Ctype(ThisDrawing.AcadDocument, AcadDocument)

    ‘Public Properties
    Public Shared ReadOnly Property ThisAcad as Application
    Get
    Return Application.AcadApplication
    End Get
    End Property

    Public Shared ReadOnly Property ThisDrawing as Document
    Get
    Return Application.DocumentManager.MdiActiveDocument
    End Get
    End Property

    ‘Methods
    (Autodesk.AutoCAD.Runtime.CommandMethod("Start", "Start", _ Autodesk.AutoCAD.Runtime.CommandFlags.Modal)> _
    Public Sub Start()
    ‘Create a new PaletteSet and a Palette. Add Palette to PaletteSet.
    ‘Set PaletteSet.Visible = True
    EndSub

    ‘Events
    Private Sub mThisDrawing_ObjectAdded(ByVal Obj As Object) Handles _ mThisDrawing.ObjectAdded
    ‘Do Stuff
    End Sub

    End Class

    If I were to reset mThisDrawing = Ctype(ThisDrawing.AcadDocument, AcadDocument) each time a new Document becomes the active document, would my ObjectAdded event now only apply to the new active document?

    IIRC, my ObjectAdded event will not fire until my command method has been executed from the command prompt. Why is that? It's almost as if "MyApp" is not created until the command method is executed.

    I want “MyApp” object to be a single instance. Should I declare it as: Public Shared Class Myapp?

    Overall, I want a single MyApp object and a single PaletteSet object to handle any active document the user throws at it. What should I be (not be) doing to make this so? (I should probably not be declaring a NEW PaletteSet in my command method.)
    Please use plain text.
    Contributor
    Posts: 17
    Registered: ‎09-30-2007

    Re: How to handle multiple open documents gracefully

    10-03-2007 08:59 AM in reply to: jspark
    Yes, I have been wondering, and am unclear on when exactly "MyApp" is created. I would guess that NETLOAD does not create an instance of "MyApp". In order to execute the command method, an instance of "MyApp" is created... If thats the case then I would assume a second instance of "MyApp" is NOT created when the command is ran for a second time. So I dont need to worry about multiple instances of "MyApp" object being created. What about resetting mThisDrawing each time a new document becomes the active document? Will that make the same event handler work for the new active doc? (I guess I could do some tests to figure that out, but it sounds logical...) Am I on the right track here?
    Please use plain text.
    Distinguished Contributor
    Posts: 135
    Registered: ‎07-07-2006

    Re: How to handle multiple open documents gracefully

    10-03-2007 09:37 AM in reply to: jspark
    Hi,

    In the beginning I also struggled how to do it..look into the following:

    1. Best is to let the Assembly (dll) autoload into AutoCAD, this requires a registry key.

    2. Use a "Autodesk.AutoCAD.Runtime.IExtensionApplication" in you're app. As soon as the app gets loaded (NETLOAD or AutoLoad) then this class gets Initialized.

    On the "Initialize" you can create a Shared instance of the custom class that handles the documents. (including events)

    3. In you're Custom Class (let's name it: "acEvents_Manager" or so)
    In this class there have to be the Application Reference for handling events raised by the Application (ACAD), this depends on what events you will need.
    You also need a DocumentCollection Reference(instance)
    This one DocumentBecameCurrent, DocumentCreated etc....

    4. Form the events of the DocumentCollection you'll be able to react, depending on you're goals.

    5. You can then event "listen" to database events. If a object changes, you can eval it and possibly update information displayed on a Palette.

    Samples etc, of these can be found in this NG.
    Search for the following:
    "Autoload dll"
    "IExtensionApplication"
    "DocumentCollection"

    ps. You should also download the "ObjectARX SDK (2008)"
    There samples and documentation regarding .NET in it.
    It helped me a lot.
    (i You need it I can upload a sample in VB.net)

    I use the following config:
    AutoCAD 2008, VS2005, WinXP sp2

    Good luck,
    A. Caddie
    Please use plain text.
    Contributor
    Posts: 17
    Registered: ‎09-30-2007

    Re: How to handle multiple open documents gracefully

    10-03-2007 09:59 AM in reply to: jspark
    That is very helpful, thank you. I will search the NG using your suggestions. I did assume I would need to handle the DocumentCollection events in order to keep "mThisDrawing" up to date with the active document. Will my application class need to "Inherit" IExtensionApplication? I am not sure what you mean by "Use "Autodesk.AutoCAD.Runtime.IExtensionApplication" in you're app". I will look into the IExtensionAppliciation. You also suggested that I create a new class for handling events. Is it "ok" to handel events within my main application class?
    Please use plain text.
    *CADJunkie

    Re: How to handle multiple open documents gracefully

    10-03-2007 10:04 AM in reply to: jspark
    What a nice professional response. You must have had some good action last
    night :-)

    Davis
    "Tony Tanzillo" wrote in message
    news:5739091@discussion.autodesk.com...
    I suppose that if you've been using VBA and its
    'ThisDrawing' object, you might become confused
    by what you take for granted.

    In VBA, 'ThisDrawing' looks like a variable, but is
    in reality, more like a function that always returns
    the Active document in the editor.

    So in .NET, rather than assigning a variable to
    the result of your GetDoc() function (which I
    presume returns the active document), you must
    call the GetDoc() function when want the Active
    document (or to make it easier, you can add a
    property to your class called 'ThisDrawing', and
    in the 'getter' for it, just return the active doc).

    When you're working with palettes, you should
    never cache a document object in a variable. You
    should always reference the MdiActiveDocument
    property of the DocumentCollection directly, when
    an operation begins, and then use that value only
    for the duration of the operation. An 'operation'
    means when the user clicks a button on your
    user interface, and in response, you access the
    active document to do something.

    What is also not obvious about VBA's 'ThisDrawing',
    is that when you handle an event of 'ThisDrawing',
    the event is fired for every open document, not
    just the one that was active when the event was
    assigned.

    In .NET, things are not as simple or automatic as
    they are in VBA.

    In .NET a Document object represents a single
    Document open in the editor, that has its own
    events. When you add a handler for a Document
    event to a Document, the handler only receives
    notification for the event in the Document that
    you added the handler to. So, to handle the same
    document event in every document, you must
    add the handler for the event to every document
    manually.

    In order to do that, you handle the events of the
    DocumentCollection (Application.DocumentManager),
    like DocumentAdded, and DocumentToBeDestroyed,
    and in the handlers for those events, you must add
    or remove your document event handlers to the
    newly added, or about-to-be closed document.

    If your app is not loaded at startup, then you also
    have to iterate over the collection of currently open
    documents, and add document events handlers to
    each of them.

    There's sample code showing how to do this on my
    website, but its in C#. There may be someone here
    that has converted it to VB.NET.


    --
    http://www.caddzone.com

    AcadXTabs: MDI Document Tabs for AutoCAD 2008
    Supporting AutoCAD 2000 through 2008
    http://www.acadxtabs.com

    wrote in message news:5738738@discussion.autodesk.com...
    I have a .NET app that is loaded with the NETLOAD command. I have a single
    command method that loads a custom control into a palette, and displays it.
    Whenever my code needs a reference to "ThisDrawing", "ThisAcad", "ThisDB"
    etc... it is gotten from a function that returns the needed reference. That
    said I have a few questions:

    Why do my event handlers (the app in general) only become active after I
    type the command for my command method? Why are they not functional after
    the NETLOAD command? Is my application object (the class that contains my
    command method and my withevents member declarations) only instantiated when
    a command method is called?

    Why does my app stop working when a new drawing is opened if the AcadApp,
    Document, Editor, Database etc.. references are gotten from a function?
    Example:

    Dim WithEvents ThisDrawing as Document = GetDoc()

    I think I am incorrectly assuming that each time my code uses ThisDrawing,
    it's the same as calling GetDoc(). Maybe I should explicitly set ThisDrawing
    = GetDoc() each time a new drawing becomes active?

    Any other tips on gracefully handling the transition from active document to
    active document will be much appreciated as well.

    TIA
    Please use plain text.
    Valued Contributor
    Posts: 67
    Registered: ‎09-12-2006

    Re: How to handle multiple open documents gracefully

    10-03-2007 10:49 AM in reply to: jspark
    It would be better to download the SDK and read everything concerning the entrypoint of an application. The method is simple enough and the examples are good.
    The entrypoint is just a method of one of your classes that is executed during load time. You just have to declare it in a certain way. It's simple enough after you see the examples.
    After you implement it, you can decide whether you want to store your variables in static variables and create a new instance of your class for every drawing or whatever.
    Please use plain text.