Author Topic: DocumentCollection Event Handler(s)  (Read 14286 times)

0 Members and 1 Guest are viewing this topic.

BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #15 on: September 22, 2012, 12:10:58 PM »
Not sure if it will cause a problem but without this class being static AutoCAD is going to want to create a new instance for every document you open. Thats going to register a stack of events which isn't what you want.  I'm not sure if this is what will happen with this code but that is what I think will happen.

Could you (or someone else) please elaborate on this, as I am not understanding how this could 'create a new instance for every document' opened?  :?

Unless I'm overlooking something, this adaptation of my earlier pseudo code demonstrates that only one (1) instance of the Event handler is being added (for the session, as incremented by i):

** Method group conversion syntax used

Code - C#: [Select]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.Runtime;
  4.  
  5. using acApp = Autodesk.AutoCAD.ApplicationServices.Application;
  6.  
  7. using System;
  8.  
  9. [assembly: ExtensionApplication(typeof(FOO.SampleEvents))]
  10.  
  11. namespace FOO
  12. {
  13.     public class SampleEvents : IExtensionApplication
  14.     {
  15.         int i = 0;
  16.  
  17.         void IExtensionApplication.Initialize()
  18.         {
  19.             acApp.DocumentManager.DocumentActivated += acDocs_DocumentActivated;
  20.  
  21.             i++;
  22.         }
  23.  
  24.         void IExtensionApplication.Terminate()
  25.         {
  26.             acApp.DocumentManager.DocumentActivated -= acDocs_DocumentActivated;
  27.         }
  28.  
  29.         public void acDocs_DocumentActivated(Object sender, DocumentCollectionEventArgs e)
  30.         {
  31.             if (e.Document != null)
  32.             {
  33.                 e.Document.Editor.WriteMessage("\n** DocumentActivated: ({0}) ** \n",
  34.                     i
  35.                     );
  36.             }
  37.         }
  38.     }
  39. }
  40.  
"How we think determines what we do, and what we do determines what we get."

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: DocumentCollection Event Handler(s)
« Reply #16 on: September 22, 2012, 12:43:02 PM »
Hi,

The Initialize() method only runs once at session startup.
You have to increment 'i' from within the event handler method:

PS: IMO there's no need to unregister the event in the Terminate() method because it runs when the session closed.

Code - C#: [Select]
  1.     public class SampleEvents : IExtensionApplication
  2.     {
  3.         int i = 0;
  4.  
  5.         void IExtensionApplication.Initialize()
  6.         {
  7.             acApp.DocumentManager.DocumentActivated += acDocs_DocumentActivated;
  8.         }
  9.  
  10.         void IExtensionApplication.Terminate()
  11.         {
  12.         }
  13.  
  14.         public void acDocs_DocumentActivated(Object sender, DocumentCollectionEventArgs e)
  15.         {
  16.             if (e.Document != null)
  17.             {
  18.                 e.Document.Editor.WriteMessage("\n** DocumentActivated: ({0}) ** \n",
  19.                     ++i
  20.                     );
  21.             }
  22.         }
  23.     }
« Last Edit: September 22, 2012, 12:46:28 PM by gile »
Speaking English as a French Frog

BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #17 on: September 22, 2012, 12:55:07 PM »
Gile,

Thanks for replying.

I think you may be missing the point of my question... The concern is over creating multiple instances of this Event handler, and not incrementing i with each run of its callback function.

Thanks for also clarifying the Terminat() question.
"How we think determines what we do, and what we do determines what we get."

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: DocumentCollection Event Handler(s)
« Reply #18 on: September 22, 2012, 01:40:59 PM »
Sorry, I'm to certain to understand what you mean with: "creating multiple instances of this Event handler"

You do not need to create multiple instances of a DocumentCollection event handler to run its event handler in each document. The upper code prints the string in each document.

Maybe you want to create multiple instances of a Document event handler (one for each opened document).
If so, here's a little sample registering the Document event handler for each new activated Document.
Notice you need to register the handler for active Document from the Initialize() method and from a DocumentCollection handler for the next documents which may be opened.
To avoid to register the Document event handler more then once while switching between opened documents, a way is to first unregister it (even if it's not already registered).

Code - C#: [Select]
  1.     public class SampleEvents : IExtensionApplication
  2.     {
  3.         void IExtensionApplication.Initialize()
  4.         {
  5.             DocumentCollection docMan = acApp.DocumentManager;
  6.             docMan.DocumentActivated += acDocs_DocumentActivated;
  7.             docMan.MdiActiveDocument.CommandWillStart += Document_CommandWillStart;
  8.         }
  9.  
  10.         void IExtensionApplication.Terminate()
  11.         {
  12.         }
  13.  
  14.         public void acDocs_DocumentActivated(Object sender, DocumentCollectionEventArgs e)
  15.         {
  16.             if (e.Document != null)
  17.             {
  18.                 e.Document.CommandWillStart -= Document_CommandWillStart;
  19.                 e.Document.CommandWillStart += Document_CommandWillStart;
  20.             }
  21.         }
  22.  
  23.         void Document_CommandWillStart(object sender, CommandEventArgs e)
  24.         {
  25.             acApp.ShowAlertDialog(e.GlobalCommandName);
  26.         }
  27.     }
Speaking English as a French Frog

TheMaster

  • Guest
Re: DocumentCollection Events Handler(s)
« Reply #19 on: September 22, 2012, 11:05:37 PM »


If you add an event handler during the document created event, you should remove it when the Document to be destroyed event takes place.


Sorry, that's not true.

Events that are members of the Document class are fired by the Document, only as long as it exists. Once a document is destroyed, all events and the handlers added to them are destroyed as well, and so after the document is destroyed, those events will never fire.

It's not necessary to remove handlers for document events if you want them to handle the events for the life of the document.

TheMaster

  • Guest
Re: DocumentCollection Event Handler(s)
« Reply #20 on: September 23, 2012, 12:39:48 AM »
Not sure if it will cause a problem but without this class being static AutoCAD is going to want to create a new instance for every document you open. Thats going to register a stack of events which isn't what you want.  I'm not sure if this is what will happen with this code but that is what I think will happen.

Could you (or someone else) please elaborate on this, as I am not understanding how this could 'create a new instance for every document' opened?  :?


He was referring to the sample code from the Developer's guide.

It shows non-static/shared command methods.

When a command method is not static/shared, AutoCAD creates multiple instances of the class that declares the method, one for each document the command is used  in. In the case of that example, the code that adds the handlers to the events are in a command method, so the only way the events would be added multiple times is if the command was invoked multiple times. 

I would be careful with those docs and the included sample code. Much of it is clearly the work of inexperienced writers.


« Last Edit: September 23, 2012, 06:45:20 PM by TT »

BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #21 on: September 23, 2012, 11:46:22 AM »
You do not need to create multiple instances of a DocumentCollection event handler to run its event handler in each document.

Events that are members of the Document class are fired by the Document, only as long as it exists. Once a document is destroyed, all events and the handlers added to them are destroyed as well, and so after the document is destroyed, those events will never fire.

It's not necessary to remove handlers for document events if you want them to handle the events for the life of the document.

When a command method is not static/shared, AutoCAD creates multiple instances of the class that declares the method, one for each document the command is used  in. In the case of that example, the code that adds the handlers to the events are in a command method, so they only way the events would be added multiple times is if the command was invoked multiple times. 

I would be careful with those docs and the included sample code. Much of it is clearly the work of inexperienced writers.

Thank you gentlemen, I greatly appreciate your help! :beer:
"How we think determines what we do, and what we do determines what we get."

BillZndl

  • Guest
Re: DocumentCollection Events Handler(s)
« Reply #22 on: September 24, 2012, 07:05:49 AM »


If you add an event handler during the document created event, you should remove it when the Document to be destroyed event takes place.


Sorry, that's not true.

Events that are members of the Document class are fired by the Document, only as long as it exists. Once a document is destroyed, all events and the handlers added to them are destroyed as well, and so after the document is destroyed, those events will never fire.

It's not necessary to remove handlers for document events if you want them to handle the events for the life of the document.

Thanks for the correction Tony.
Can't remember how I came to that (wrong) conclusion.  :oops:

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: DocumentCollection Event Handler(s)
« Reply #23 on: September 24, 2012, 08:11:11 AM »

Could you (or someone else) please elaborate on this, as I am not understanding how this could 'create a new instance for every document' opened?  :?


What Tony said.  :-)
Revit 2019, AMEP 2019 64bit Win 10

BillZndl

  • Guest
Re: DocumentCollection Event Handler(s)
« Reply #24 on: September 25, 2012, 01:52:54 PM »
If you add an event handler during the document created event, you should remove it when the Document to be destroyed event takes place.
Sorry, that's not true.
Events that are members of the Document class are fired by the Document, only as long as it exists. Once a document is destroyed, all events and the handlers added to them are destroyed as well, and so after the document is destroyed, those events will never fire.
It's not necessary to remove handlers for document events if you want them to handle the events for the life of the document.

This begs a question:

If you can add an event handler to an open document and leave it there for the life of the document,
is there any benefit to removing event handlers from a document when the handler is not in use?

My Example: When my App initializes,
I  add "Document.CommandWillStart += new CommandEventHandler(Document_CommandWillStart);" to all open documents in AutoCAD
and to any newly created documents during the session.

Then I check for "ClassicGroup" command in my callback for "CommandWIllStart"
and if "ClassicGroup" is the command, I add more event handlers (CommandCancelled, CommandEnded and CommandFailed) to the MDIActiveDocument.

When "ClassicGroup" is Ended/Cancelled/Failed, I do my work accordingly in the CommandEnded/Cancelled/Failed callback and I also remove "-=" the CommandCancelled, CommandEnded and CommandFailed handlers from the MDIActiveDocument.

I have been under the impression that removing the unused handlers was to avoid memory issues during the session.
Do I really have to remove the document event handlers at all?


TIA



Jeff H

  • Needs a day job
  • Posts: 6150
Re: DocumentCollection Event Handler(s)
« Reply #25 on: September 25, 2012, 03:10:57 PM »
Examples I have seen by autodesk I can see how they might convey that.
 
The object that 'publishes' the events is the one that holds an reference to subscribers.
Subscribing to documents events will not cause the document object to live any longer or not get GC.
The document object will keep your class that hold the subscribed handlers from being collected until it is collected.
 


 

 
 

BillZndl

  • Guest
Re: DocumentCollection Event Handler(s)
« Reply #26 on: September 25, 2012, 04:22:34 PM »
Examples I have seen by autodesk I can see how they might convey that.
 
The object that 'publishes' the events is the one that holds an reference to subscribers.
Subscribing to documents events will not cause the document object to live any longer or not get GC.
The document object will keep your class that hold the subscribed handlers from being collected until it is collected.

And since the class that holds the subscribed handlers is static and lives until the App closes,
what happens if I close my app before autocad closes?
Will I get a Kaboom, because the documents are still alive?


Jeff H

  • Needs a day job
  • Posts: 6150
Re: DocumentCollection Event Handler(s)
« Reply #27 on: September 25, 2012, 06:17:57 PM »
Examples I have seen by autodesk I can see how they might convey that.
 
The object that 'publishes' the events is the one that holds an reference to subscribers.
Subscribing to documents events will not cause the document object to live any longer or not get GC.
The document object will keep your class that hold the subscribed handlers from being collected until it is collected.

And since the class that holds the subscribed handlers is static and lives until the App closes,
what happens if I close my app before autocad closes?
Will I get a Kaboom, because the documents are still alive?
Would'nt Autocad have to be closing if your app is closing?
 

TheMaster

  • Guest
Re: DocumentCollection Event Handler(s)
« Reply #28 on: September 25, 2012, 07:26:45 PM »
If you add an event handler during the document created event, you should remove it when the Document to be destroyed event takes place.
Sorry, that's not true.
Events that are members of the Document class are fired by the Document, only as long as it exists. Once a document is destroyed, all events and the handlers added to them are destroyed as well, and so after the document is destroyed, those events will never fire.
It's not necessary to remove handlers for document events if you want them to handle the events for the life of the document.

This begs a question:

If you can add an event handler to an open document and leave it there for the life of the document,
is there any benefit to removing event handlers from a document when the handler is not in use?

My Example: When my App initializes,
I  add "Document.CommandWillStart += new CommandEventHandler(Document_CommandWillStart);" to all open documents in AutoCAD
and to any newly created documents during the session.

Then I check for "ClassicGroup" command in my callback for "CommandWIllStart"
and if "ClassicGroup" is the command, I add more event handlers (CommandCancelled, CommandEnded and CommandFailed) to the MDIActiveDocument.

When "ClassicGroup" is Ended/Cancelled/Failed, I do my work accordingly in the CommandEnded/Cancelled/Failed callback and I also remove "-=" the CommandCancelled, CommandEnded and CommandFailed handlers from the MDIActiveDocument.

I have been under the impression that removing the unused handlers was to avoid memory issues during the session.
Do I really have to remove the document event handlers at all?

TIA


Yes, if they have overhead. The Command-related events can have overhead especially when commands are being scripted at a high-frequency by other customization, namely LISP.

The way you're doing it with the Command events is IMO, the right way to do it, since you don't want your event handlers called when every command is ended/cancelled.

TheMaster

  • Guest
Re: DocumentCollection Event Handler(s)
« Reply #29 on: September 25, 2012, 07:36:59 PM »
Examples I have seen by autodesk I can see how they might convey that.
 
The object that 'publishes' the events is the one that holds an reference to subscribers.
Subscribing to documents events will not cause the document object to live any longer or not get GC.
The document object will keep your class that hold the subscribed handlers from being collected until it is collected.

And since the class that holds the subscribed handlers is static and lives until the App closes,
what happens if I close my app before autocad closes?
Will I get a Kaboom, because the documents are still alive?

I'm not sure what you mean by 'close my app'.

If the handler is not static, then there has to be an instance of the class containing the non-static methods, which the handler must be invoked through. So, as long as the handler is added to the event, that instance will not be collected, but in any case, when the instance of the class containing the event handlers is no longer needed, you should remove its handlers from any events because you (presumably) aren't interested in those events any longer.

There are also what are referred to as 'Weak' events. A weak event will only fire the event at a handler if the object that handles the event is still alive (e.g., hasn't been collected). A weak event also does not prevent the object that handles the weak event from being collected. I'm not aware of any use of weak events in AutoCAD's API but I haven't searched it lately for any and there may be some in WPF code like the Ribbon, or what have you.