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

0 Members and 1 Guest are viewing this topic.

BlackBox

  • King Gator
  • Posts: 3770
DocumentCollection Event Handler(s)
« on: September 08, 2012, 12:49:24 PM »
I'm trying to develop an Event handler DocumentCollection Events, for several different purposes, not necessarily in the same solution.

I am adept at coding Visual LISP Reactors, and I know there's more to Event monitors than VL requires... Are there any good tutorials, or samples from which I can learn?

TIA

** Edit - Revised thread title, and OP for clarity.
« Last Edit: September 21, 2012, 08:46:02 AM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: DocumentMonitor
« Reply #1 on: September 08, 2012, 02:16:20 PM »
The ObjectARX kit has a good example of events in the EventsWatcher sample code. On my system it's here:
C:\ObjectARX 2012\samples\dotNet\EventsWatcher

TheMaster

  • Guest
Re: DocumentMonitor
« Reply #2 on: September 08, 2012, 06:59:02 PM »
I'm trying to develop a DocumentMonitor for handling DocumentManager Events, for several different purposes, not necessarily in the same solution.

I am adept at coding Visual LISP Reactors, and I know there's more to Event monitors than VL requires... Are there any good tutorials, or samples from which I can learn?

TIA

I use a class called DocumentManager that allows me to add/remove document-level events when documents are opened/closed. But there's two basic ways it's used. In some cases, the events for all documents are handled by a single object, and in other cases, there are multiple instances of an object, one for each open document, that are created when a document is added to the DocumentCollection, and discarded/disposed when the document is destroyed.

I think I may have posted some older iterations of that class here.

So, how to approach it depends on whether you want per-document instances of an object, where each instance is associated with a single document, and handles the events of the document, or if you want to have a single instance that handles events for all documents (or a static class that does the same).


BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentMonitor
« Reply #3 on: September 08, 2012, 07:05:43 PM »
I should have checked the ObjectARX SDK before posting... the Civil 3D samples are pretty much the same (at least for the versions I have installed), so I sometimes discount them to search online.

For the task I am attempting to complete, I believe a single object would do, as I only need it to act once for each document when it is added/opened. Also thanks for reminding me that a single object is possible, as my initial thought was to create one for each document, which would not be necessary.

Not really sure of the difference or advantage between a single Object, and/or a Static Class in this context.

As always, thanks for the guidance, Jeff & Tony. :beer:
"How we think determines what we do, and what we do determines what we get."

Jeff H

  • Needs a day job
  • Posts: 6144
Re: DocumentMonitor
« Reply #4 on: September 09, 2012, 02:46:31 PM »

BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentMonitor
« Reply #5 on: September 10, 2012, 09:47:07 AM »
Thanks for the link, Jeff!
"How we think determines what we do, and what we do determines what we get."

BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #6 on: September 19, 2012, 08:38:05 AM »
This is still a work in progress on my part. Currently, I am using a registry key to auto-[NET]load my assembly into each of my sessions, and 'register' my Event handler (+=) via IExtensionApplication.Initialize().

If all I am attempting to handle is the DocumentCreated Event, should I be using DocumentToBeDestroyed Event to clean up anything, or is relying on IExtensionApplication.Terminate() to remove (-=) the Event handler sufficient?

** Edit - For example, when saving & closing a document that has an Event handler.

I just want to make sure that I am not overlooking something important, or mishandling Events, etc. (no pun intended).

TIA
« Last Edit: September 21, 2012, 08:46:21 AM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

BillZndl

  • Guest
Re: DocumentCollection Events Handler(s)
« Reply #7 on: September 19, 2012, 09:57:17 AM »
This is still a work in progress on my part. Currently, I am using a registry key to auto-[NET]load my assembly into each of my sessions, and 'register' my Event handler (+=) via IExtensionApplication.Initialize().

If all I am attempting to handle is the DocumentCreated Event, should I be using DocumentToBeDestroyed Event to clean up anything, or is relying on IExtensionApplication.Terminate() to remove (-=) the Event handler sufficient?

** Edit - For example, when saving & closing a document that has an Event handler.

I just want to make sure that I am not overlooking something important, or mishandling Events, etc. (no pun intended).

TIA


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

Code: [Select]
void DocumentManager_DocumentCreated(object sender, DocumentCollectionEventArgs e)
        {           
            e.Document.CommandWillStart += new CommandEventHandler(Document_CommandWillStart);           
        }

        void DocumentManager_DocumentToBeDestroyed(object sender, DocumentCollectionEventArgs e)
        {           
            if (e.Document != null)
                e.Document.CommandWillStart -= new CommandEventHandler(Document_CommandWillStart);               
        }


BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #8 on: September 19, 2012, 10:01: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.

That's exactly what I needed to know... I had seen several examples (those posted above, and others), and only one or two included the DocumentToBeDestroyed Callback, let alone removed the Event handler. Not even SpiderInNet1 had it here (and they're usually on point, in my novice opinion)

Cheers! :beer:
« Last Edit: September 21, 2012, 08:46:31 AM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

BillZndl

  • Guest
Re: DocumentCollection Events Handler(s)
« Reply #9 on: September 19, 2012, 10:41:14 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.

That's exactly what I needed to know... I had seen several examples (those posted above, and others), and only one or two included the DocumentToBeDestroyed Callback, let alone removed the Event handler. Not even SpiderInNet1 had it here (and they're usually on point, in my novice opinion)

Cheers! :beer:

Depending on what you are doing and when your app starts,
you may want to consider adding event handlers to any documents that may already be open (along with the rest of your event handlers).
Here's what I use, called from IExtensionApplication.Initialize().

Code: [Select]
public void AddEventHandlersToOpenDocs()
        {
            try
            {
                DocumentCollection documents = AcadApp.DocumentManager;

                foreach (Document Document in documents)
                {
                    Document.CommandWillStart += new CommandEventHandler(Document_CommandWillStart);                   
                }

                AcadApp.DocumentManager.DocumentActivated += new DocumentCollectionEventHandler(DocumentManager_DocumentActivated);               
                AcadApp.DocumentManager.DocumentCreated += new DocumentCollectionEventHandler(DocumentManager_DocumentCreated);
                AcadApp.DocumentManager.DocumentToBeDestroyed += new DocumentCollectionEventHandler(DocumentManager_DocumentToBeDestroyed);
            }
            catch (Exception exception)
            {
                MessageBox.Show(" EventHandlers kaputt! " + exception.Message);
            }
        }


BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #10 on: September 21, 2012, 08:28:19 AM »
My inexperience with .NET Events may have led to my not asking the appropriate question(s) earlier, so I will try to be more specific... I understand (now, thanks BillZndl) that Document Events must be unregistered (-=) for each Document prior to being Destroyed.

Quote from: Autodesk Exchange, AutoCAD, Help, AutoCAD .NET Developer's Guide, Use Events, Handle Document Events

Handle Document Events

Document object events are used to respond to the document window. When a document event is registered, it is only associated with the document object in which it is associated. So if an event needs to be registered with each document, you will want to use the DocumentCreated event of the DocumentCollection object to register events with each new or opened drawing.

<snip>

However, as I am only attempting to monitor DocumentCollection Events in order to invoke a simple Method (which uses FindFile() & System.IO), when the DocumentCreated Event and\or the DocumentActivated Event fires... If I am understanding this correctly:

Quote from: Autodesk Exchange, AutoCAD, Help, AutoCAD .NET Developer's Guide, Use Events, Handle DocumentCollection Events (.NET)

Handle DocumentCollection Events

DocumentCollection events, unlike Document object events, remain registered until AutoCAD is shutdown or until they are unregistered.

<snip>

... I need only to unregister (-=) the DocumentCollectionEventHandler(s) upon IExtensionApplication.Terminate(), since it is being registered (+=) upon IExtensionApplication.Initialize(), no?

Pseudo code:
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. using System.IO;
  9.  
  10. [assembly: ExtensionApplication(typeof(FOO.SampleEvents))]
  11.  
  12. namespace FOO
  13. {
  14.     public class SampleEvents : IExtensionApplication
  15.     {
  16.         //DocumentCollection acDocs;
  17.  
  18.         void IExtensionApplication.Initialize()
  19.         {
  20.             DocumentCollection acDocs = acApp.DocumentManager;
  21.  
  22.             acDocs.DocumentCreated +=
  23.                 new DocumentCollectionEventHandler(acDocs_DocumentCreated);
  24.  
  25.             acDocs.DocumentActivated +=
  26.                 new DocumentCollectionEventHandler(acDocs_DocumentActivated);
  27.  
  28.             acDocs.MdiActiveDocument.Editor.WriteMessage(
  29.                 "\n** DocumentCollectionEventHandler loaded ** \n"
  30.                 );
  31.         }
  32.  
  33.         void IExtensionApplication.Terminate()
  34.         {
  35.             DocumentCollection acDocs = acApp.DocumentManager;
  36.  
  37.             acDocs.DocumentCreated -=
  38.                 new DocumentCollectionEventHandler(acDocs_DocumentCreated);
  39.  
  40.             acDocs.DocumentActivated -=
  41.                 new DocumentCollectionEventHandler(acDocs_DocumentActivated);
  42.         }
  43.  
  44.         public void acDocs_DocumentCreated(Object sender, DocumentCollectionEventArgs e)
  45.         {
  46.             if (e.Document != null)
  47.             {
  48.                 e.Document.Editor.WriteMessage("\n** DocumentCreated: ({0}) ** \n",
  49.                     Path.GetFileName(e.Document.Name)
  50.                     );
  51.             }
  52.         }
  53.  
  54.         public void acDocs_DocumentActivated(Object sender, DocumentCollectionEventArgs e)
  55.         {
  56.             if (e.Document != null)
  57.             {
  58.                 e.Document.Editor.WriteMessage("\n** DocumentActivated: ({0}) ** \n",
  59.                     Path.GetFileName(e.Document.Name)
  60.                     );
  61.             }
  62.         }
  63.     }
  64. }
  65.  
« Last Edit: September 21, 2012, 08:47:03 AM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: DocumentCollection Event Handler(s)
« Reply #11 on: September 21, 2012, 01:52:38 PM »
... I need only to unregister (-=) the DocumentCollectionEventHandler(s) upon IExtensionApplication.Terminate(), since it is being registered (+=) upon IExtensionApplication.Initialize(), no?

Yes.

I use a shorthand version of event registering. Don't know what the difference is.
Code: [Select]
acDocs.DocumentCreated += acDocs_DocumentCreated;

and
Code: [Select]
acDocs.DocumentCreated -= acDocs_DocumentCreated;
« Last Edit: September 21, 2012, 01:57:50 PM by MexicanCustard »
Revit 2019, AMEP 2019 64bit Win 10

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: DocumentCollection Event Handler(s)
« Reply #12 on: September 21, 2012, 02:02:40 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.
Revit 2019, AMEP 2019 64bit Win 10

BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #13 on: September 21, 2012, 02:56:17 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.

I really don't know, but I would very much like to avoid that... Hence my seeking clarity.

The pseudo code I posted, was an adaptation of that which is provided in the online documentation (linked above):

Quote from: Autodesk Exchange, AutoCAD, Help, AutoCAD .NET Developer's Guide, Use Events, Handle DocumentCollection Events (.NET)
Code - C#: [Select]
  1. using Autodesk.AutoCAD.Runtime;
  2. using Autodesk.AutoCAD.ApplicationServices;
  3.  
  4. [CommandMethod("AddDocColEvent")]
  5. public void AddDocColEvent()
  6. {
  7.   Application.DocumentManager.DocumentActivated +=
  8.       new DocumentCollectionEventHandler(docColDocAct);
  9. }
  10.  
  11. [CommandMethod("RemoveDocColEvent")]
  12. public void RemoveDocColEvent()
  13. {
  14.   Application.DocumentManager.DocumentActivated -=
  15.       new DocumentCollectionEventHandler(docColDocAct);
  16. }
  17.  
  18. public void docColDocAct(object senderObj,
  19.                          DocumentCollectionEventArgs docColDocActEvtArgs)
  20. {
  21.   Application.ShowAlertDialog(docColDocActEvtArgs.Document.Name +
  22.                               " was activated.");
  23. }
  24.  

Again, I'm just trying to make sure that I learn some best practices for Events; I know the documentation is notorious for being incomplete, etc. and wanted to see if I am headed in the right direction, and not making any blatant mistakes moving forward.
"How we think determines what we do, and what we do determines what we get."

BlackBox

  • King Gator
  • Posts: 3770
Re: DocumentCollection Event Handler(s)
« Reply #14 on: September 22, 2012, 11:25:36 AM »
After some reading, I was able to find some clarification on this 'shorthand' syntax:

I use a shorthand version of event registering. Don't know what the difference is.
Code: [Select]
acDocs.DocumentCreated += acDocs_DocumentCreated;

and
Code: [Select]
acDocs.DocumentCreated -= acDocs_DocumentCreated;

... It's called  'method group conversion'; I've also included some additional excerpts from Andrew's book regarding listening to, and simplifying the registration of, Events:



Quote from: Andrew Troelsen - Pro C# 2010 and the .NET 4.0 Platform, Fifth Edition, Page 422

Listening to Incoming Events

C# events also simplify the act of registering the caller-side event handlers. Rather than having to specify
custom helper methods, the caller simply makes use of the += and -= operators directly (which triggers
the correct add_XXX() or remove_XXX() method in the background). When you wish to register with an
event, follow the pattern shown here:

Code - C#: [Select]
  1. // NameOfObject.NameOfEvent += new RelatedDelegate(functionToCall);
  2. //
  3. Car.EngineHandler d = new Car.CarEventHandler(CarExplodedEventHandler)
  4. myCar.Exploded += d;
  5. When you wish to detach from a source of events, use the -= operator, using the following pattern
  6. // NameOfObject.NameOfEvent -= new RelatedDelegate(functionToCall);
  7. //
  8. myCar.Exploded -= d;
  9.  

Given these very predictable patterns, here is the refactored Main() method, now using the C# event
registration syntax:

Code - C#: [Select]
  1.     class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             Console.WriteLine("***** Fun with Events *****\n");
  6.             Car c1 = new Car("SlugBug", 100, 10);
  7.  
  8.             // Register event handlers.
  9.             c1.AboutToBlow += new Car.CarEngineHandler(CarIsAlmostDoomed);
  10.             c1.AboutToBlow += new Car.CarEngineHandler(CarAboutToBlow);
  11.             Car.CarEngineHandler d = new Car.CarEngineHandler(CarExploded);
  12.  
  13.             c1.Exploded += d;
  14.  
  15.             Console.WriteLine("***** Speeding up *****");
  16.  
  17.             for (int i = 0; i < 6; i++)
  18.                 c1.Accelerate(20);
  19.  
  20.             // Remove CarExploded method
  21.             // from invocation list.
  22.             c1.Exploded -= d;
  23.  
  24.             Console.WriteLine("\n***** Speeding up *****");
  25.  
  26.             for (int i = 0; i < 6; i++)
  27.                 c1.Accelerate(20);
  28.  
  29.             Console.ReadLine();
  30.         }
  31.  
  32.         public static void CarAboutToBlow(string msg)
  33.         { Console.WriteLine(msg); }
  34.  
  35.         public static void CarIsAlmostDoomed(string msg)
  36.         { Console.WriteLine("=> Critical Message from Car: {0}", msg); }
  37.  
  38.         public static void CarExploded(string msg)
  39.         { Console.WriteLine(msg); }
  40.     }
  41.  

To even further simplify event registration, you can use method group conversion. Consider the
following iteration of Main():

Code - C#: [Select]
  1.         static void Main(string[] args)
  2.         {
  3.             Console.WriteLine("***** Fun with Events *****\n");
  4.             Car c1 = new Car("SlugBug", 100, 10);
  5.  
  6.             // Register event handlers.
  7.             c1.AboutToBlow += CarIsAlmostDoomed;
  8.             c1.AboutToBlow += CarAboutToBlow;
  9.             c1.Exploded += CarExploded;
  10.  
  11.             Console.WriteLine("***** Speeding up *****");
  12.  
  13.             for (int i = 0; i < 6; i++)
  14.                 c1.Accelerate(20);
  15.  
  16.             c1.Exploded -= CarExploded;
  17.  
  18.             Console.WriteLine("\n***** Speeding up *****");
  19.  
  20.             for (int i = 0; i < 6; i++)
  21.                 c1.Accelerate(20);
  22.  
  23.             Console.ReadLine();
  24.         }
  25.  



Simplifying Event Registration Using Visual Studio 2010

Visual Studio 2010 offers assistance with the process of registering event handlers. When you apply the
+= syntax during event registration, you will find an IntelliSense window displayed, inviting you to hit the
Tab key to autocomplete the associated delegate instance (see Figure 11-2)

(see 11-2_delegate_selection_intellisense.bmp)

After you hit the Tab key, you are invited to enter the name of the event handler to be generated (or
simply accept the default name) as shown in Figure 11-3.

(see 11-3_delegate_target_format_intellisense.bmp)

When you hit the Tab key again, you will be provided with stub code in the correct format of the
delegate target (note that this method has been declared static due to the fact that the event was
registered within the static Main() method):

Code - C#: [Select]
  1.         static void newCar_AboutToBlow(string msg)
  2.         {
  3.             // Add your code!
  4.         }
  5.  

IntelliSense is available to all .NET events in the base class libraries. This IDE feature is a massive
time-saver, given that it saves you from having to search the .NET help system to figure out both the
correct delegate to use with a particular event and the format of the delegate target method.
"How we think determines what we do, and what we do determines what we get."

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: 6144
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: 6144
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.

BillZndl

  • Guest
Re: DocumentCollection Event Handler(s)
« Reply #30 on: September 26, 2012, 07:29:18 AM »
Would'nt Autocad have to be closing if your app is closing?
I'm not sure what you mean by 'close my app'.

Just to clarifly:

My "App" netloads and shows a modeless form and populates a listview with the names of any AutoCAD "Groups" that exist in the drawing.
The command and database event handlers watch for when new groups are added to the database and adds a "date created" to the description field of the group.

The "App" runs off an "instance" of the form and I override the "OnClosing" event where the visibility of the form is set to false,
so I think the App really doesn't "Close" until AutoCAD closes.

Code: [Select]
private static PartMonitor instance = null;

public static PartMonitor Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new PartMonitor();
                }
                return instance;
            }
        }

protected override void OnClosing(CancelEventArgs e)
        {           
                base.OnClosing(e);
                e.Cancel = true;
                Visible = false;       
        }
////
public class PartMonitor1
    {       
        [CommandMethod("Partmon", CommandFlags.Session)]   
        public static void ShowModelessDialog()
        {
            Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessDialog(PartMonitor.Instance);
        }       
    }

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.

Thank you!
That was the thought process that led me to set up the event handlers that way.