Author Topic: Database.ObjectModified Event  (Read 15068 times)

0 Members and 1 Guest are viewing this topic.

BlackBox

  • King Gator
  • Posts: 3770
Database.ObjectModified Event
« on: December 07, 2012, 04:42:43 PM »
I'm trying to learn more about the Database.ObjectModified Event, and have read from articles, blog posts, etc. to try and comprehend what I can.

One concept I'm seeking to have clarified, is the seeming importance of adding the e.DbObject.Id to an ObjectIdCollection for later action (as Tony points out here), rather than simply enacting changes on the matching/desired e.DBObject.Id.ObjectClass.Name via StartOpenCloseTransaction() within the ObjectModified Event handler itself (I've read of the No, No, of using StartTransaction() WRT REDO).



The (perhaps elementary?) scenario I'll use, is to select an entity in the drawing (of any type), and manually change it's layer, which then fires the Database.ObjectModified Event (as I have not registered an ObjectModified Event for that entity)... Then to prompt the user with something simple like:

Code - C#: [Select]
  1. acApp.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
  2.     e.DBObject.Id.ObjectClass.Name + " modified "
  3. );



In this scenario, no Command is invoked, thus I'm inclined to 'act' within the ObjectModified Event handler (via StartOpenCloseTransaction() )... Which seems not only logical, but pretty commonsensical to me, but again, I'm just learning - I could be completely wrong.

Sorry, simplest that I can come up with at the moment... Obviously, for an actual plug-in, further filtering, and action would ensue. Just trying further my learning... Code examples not expected, but always appreciated.

TIA
« Last Edit: December 07, 2012, 05:00:15 PM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #1 on: December 07, 2012, 05:45:16 PM »
I threw some pseudo code together to test the StartOpenCloseTransaction(), and all seemed to be working well... That is, once I added some logical conditions beforehand:

Code - C#: [Select]
  1.  
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Internal;
  6. using Autodesk.AutoCAD.Runtime;
  7.  
  8. using acApp = Autodesk.AutoCAD.ApplicationServices.Application;
  9.  
  10. using System;
  11.  
  12. [assembly: ExtensionApplication(typeof(Foo.Bar))]
  13.  
  14. namespace Foo
  15. {
  16.     class Bar: IExtensionApplication
  17.     {
  18.         void IExtensionApplication.Initialize()
  19.         {
  20.             DocumentCollection acDocs = acApp.DocumentManager;
  21.  
  22.             // Normally I'd hook the DocumentCreated Event here
  23.            
  24.             foreach (Document doc in acDocs)
  25.                 doc.Database.ObjectModified += onObjectModified;
  26.  
  27.             acApp.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
  28.                 "\nObjectModifed demonstration "
  29.             );
  30.         }
  31.  
  32.         void IExtensionApplication.Terminate()
  33.         {
  34.         }
  35.  
  36.        // An onDocumentCreated Event handler would usually go here.
  37.  
  38.         public static void onObjectModified(object sender, ObjectEventArgs e)
  39.         {
  40.             Editor ed = acApp.DocumentManager.MdiActiveDocument.Editor;
  41.  
  42.             if (e.DBObject != null &&
  43.                 e.DBObject.IsErased != true &&
  44.                 e.DBObject.IsUndoing != true)
  45.             {
  46.                 string objName = e.DBObject.GetType().Name.ToString();
  47.  
  48.                 if (Utils.WcMatch(objName, "MText,Text,*Leader"))
  49.                 {
  50.                     Entity ent = e.DBObject as Entity;
  51.  
  52.                     ed.WriteMessage("\n[ObjectModified] : " + objName + " (" + ent.Layer + ") ");
  53.                 }
  54.             }
  55.         }
  56.  
  57.     }
  58. }
  59.  
  60.  

... I'm sure there's something I've not yet thought of, or encountered. Again, this is only a working snippet.
« Last Edit: December 08, 2012, 04:11:09 PM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

TheMaster

  • Guest
Re: Database.ObjectModified Event
« Reply #2 on: December 08, 2012, 03:46:38 PM »
Your code is using a transaction to get a managed wrapper for a currently-open database object for which you already have a managed wrapper for (the DBObject passed into the event handler).

There's no need to use a transaction in that case because the DBObject that is passed into the event handler is already open (and most-likely in state that would not allow it to be modified in any way), so you can use that DBObject directly.



« Last Edit: December 08, 2012, 03:52:08 PM by TT »

BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #3 on: December 08, 2012, 04:04:42 PM »
Your code is using a transaction to get a managed wrapper for a currently-open database object for which you already have a managed wrapper for (the DBObject passed into the event handler).

There's no need to use a transaction in that case because the DBObject that is passed into the event handler is already open (and most-likely in state that would not allow it to be modified in any way), so you can use that DBObject directly.

Thanks for the correction, Tony.

I was mistaken in thinking that the ObjectModified also implied that the ObjectClosed had occurred, and now better understand why you aptly suggested storing the ObjectId's for later action, but am unsure how to utilize that, given that no Command is being used.

I am attempting to hook the Database.ObjectModified Event, rather than manage adding an ObjectModified Event to each existing entity and all those appended to the Database thereafter.

... Is it possible to modify the Object via Database.ObjectModified, or need I register an entity level ObjectClosed Event handler during Database.ObjectModified (untested)?
"How we think determines what we do, and what we do determines what we get."

TheMaster

  • Guest
Re: Database.ObjectModified Event
« Reply #4 on: December 08, 2012, 06:11:31 PM »
Your code is using a transaction to get a managed wrapper for a currently-open database object for which you already have a managed wrapper for (the DBObject passed into the event handler).

There's no need to use a transaction in that case because the DBObject that is passed into the event handler is already open (and most-likely in state that would not allow it to be modified in any way), so you can use that DBObject directly.

Thanks for the correction, Tony.

I was mistaken in thinking that the ObjectModified also implied that the ObjectClosed had occurred, and now better understand why you aptly suggested storing the ObjectId's for later action, but am unsure how to utilize that, given that no Command is being used.

I am attempting to hook the Database.ObjectModified Event, rather than manage adding an ObjectModified Event to each existing entity and all those appended to the Database thereafter.

... Is it possible to modify the Object via Database.ObjectModified, or need I register an entity level ObjectClosed Event handler during Database.ObjectModified (untested)?

Hard to say, without seeing the larger picture. What is it you are trying to accomplish?

BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #5 on: December 08, 2012, 06:45:52 PM »
Your code is using a transaction to get a managed wrapper for a currently-open database object for which you already have a managed wrapper for (the DBObject passed into the event handler).

There's no need to use a transaction in that case because the DBObject that is passed into the event handler is already open (and most-likely in state that would not allow it to be modified in any way), so you can use that DBObject directly.

Thanks for the correction, Tony.

I was mistaken in thinking that the ObjectModified also implied that the ObjectClosed had occurred, and now better understand why you aptly suggested storing the ObjectId's for later action, but am unsure how to utilize that, given that no Command is being used.

I am attempting to hook the Database.ObjectModified Event, rather than manage adding an ObjectModified Event to each existing entity and all those appended to the Database thereafter.

... Is it possible to modify the Object via Database.ObjectModified, or need I register an entity level ObjectClosed Event handler during Database.ObjectModified (untested)?

Hard to say, without seeing the larger picture. What is it you are trying to accomplish?

Sorry for not being more clear in previous posts.

I'm toying with the idea of an 'AnnoAuto' plug-in that would (based on user-defined XML settings), automatically apply the desired annotation entity settings for each a Dimension, Leader, MText, MLeader, and Text entities, based upon the Layer these entities reside, or are placed upon.

For years I've used Command Reactors (Visual LISP) to automatically configure certain properties, current layer, etc. for me, and am now attempting to enhance that via .NET API features, and ease of gathering requirements via XML, etc..

Scenario: Add an MLeader to the drawing, where CLAYER = 0, then manually select the MLeader and move it to another layer, where that layer has predefined settings for each of the above entity types, and what settings should be applied. I'm basically attempting to make the Standards Command no longer necessary, and something that is applied during production, rather than manually invoked prior to save/close

My intent was to use the ObjectModified Event to trigger these pseudo-annotation standards being applied, but obviously need to interact (ForWrite) with the Objects themselves, and to (ForRead) access the MLeader Style, TextStyle, etc. ObjectId's as applicable via Transaction... Hope that makes (more?) sense.
"How we think determines what we do, and what we do determines what we get."

TheMaster

  • Guest
Re: Database.ObjectModified Event
« Reply #6 on: December 09, 2012, 12:56:54 AM »
Your code is using a transaction to get a managed wrapper for a currently-open database object for which you already have a managed wrapper for (the DBObject passed into the event handler).

There's no need to use a transaction in that case because the DBObject that is passed into the event handler is already open (and most-likely in state that would not allow it to be modified in any way), so you can use that DBObject directly.

Thanks for the correction, Tony.

I was mistaken in thinking that the ObjectModified also implied that the ObjectClosed had occurred, and now better understand why you aptly suggested storing the ObjectId's for later action, but am unsure how to utilize that, given that no Command is being used.

I am attempting to hook the Database.ObjectModified Event, rather than manage adding an ObjectModified Event to each existing entity and all those appended to the Database thereafter.

... Is it possible to modify the Object via Database.ObjectModified, or need I register an entity level ObjectClosed Event handler during Database.ObjectModified (untested)?

Hard to say, without seeing the larger picture. What is it you are trying to accomplish?

Sorry for not being more clear in previous posts.

I'm toying with the idea of an 'AnnoAuto' plug-in that would (based on user-defined XML settings), automatically apply the desired annotation entity settings for each a Dimension, Leader, MText, MLeader, and Text entities, based upon the Layer these entities reside, or are placed upon.

For years I've used Command Reactors (Visual LISP) to automatically configure certain properties, current layer, etc. for me, and am now attempting to enhance that via .NET API features, and ease of gathering requirements via XML, etc..


Objects can be modified when there is no running command, so how did you handle that in LISP ?


BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #7 on: December 09, 2012, 01:10:31 PM »
That's the distinction, my LISP simply didn't have this functionality.

The Command Reactor would store the current setting like Clayer, etc. and check/make/set the needed layer for say XREFs and then restore when done. I never did spend the time proper to make this Annotation aspect work in LISP (not sure that it cannot), but am progressively working to move to .NET and using small ideas like this as pilots so to speak.

I'll have to read up on the available Database Events, to better formulate this idea, as I know there's fruit to e had from it (when I get it to work)... Without having to implement an event handler for each, and every annotation entity that exists, or is appended to the Database.

Perhaps I can use the Database.ObjectModified event to store the ObjectIds then use the Database.ObjectClosed event to 'act' (without having looked in Object Browser, as I am on my iPhone at the moment).

As always, I appreciate you time and feedback to ask questions that make me think this through rather than just giving me the answer so to speak. Cheers! :beer:
"How we think determines what we do, and what we do determines what we get."

BillZndl

  • Guest
Re: Database.ObjectModified Event
« Reply #8 on: December 10, 2012, 08:01:45 AM »

Perhaps I can use the Database.ObjectModified event to store the ObjectIds then use the Database.ObjectClosed event to 'act' (without having looked in Object Browser, as I am on my iPhone at the moment).

As always, I appreciate you time and feedback to ask questions that make me think this through rather than just giving me the answer so to speak. Cheers! :beer:

Very interesting subject and one I would like to know more about.
I ran into this same problem when I tried to work on an Object when the ObjectModified event fired,
(finding that the Object was not accessible as it was still open at this time(?)).

What I did was store the ObjectId in separate Class ObjectIdCollection on the ObjectModified event.
(C#)
Code: [Select]
void Database_ObjectAppended(object sender, ObjectEventArgs e)
        {
            if (e.DBObject.GetType().Name.Equals("Group"))
            {
                Module.GrpInfoTbl.Add(e.DBObject.ObjectId);
            }
        }

public class Module
    {
        private static ObjectIdCollection OIDColl = new ObjectIdCollection();

        public static ObjectIdCollection GrpInfoTbl
        {
            get
            {
                return OIDColl;
            }
        }
        public Module()
        {
        }
    }

Then when the command that did the modifying ended, would do the work on the ObjectIds contained therein using a separate method.

Not posting this as an example because I am only a "dabbler" in programming
but am hoping to learn more about this myself on how valid of a solution this would be for the problem.



BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #9 on: December 10, 2012, 09:42:22 AM »
Perhaps I can use the Database.ObjectModified event to store the ObjectIds then use the Database.ObjectClosed event to 'act' (without having looked in Object Browser, as I am on my iPhone at the moment).

Well, as it happens, there is no such Database.ObjectClosed Event (Oops).

So the best I can determine in a quick MgdDbg test this morning, when manually selecting an entity, and changing it's layer via Properties Palette, only raises the Database.ObjectOpenedForModify, and Database.ObjectModified Events.

When I have time during lunch, I will test two scenarios:

1.)  Not sure if it's possible to register a DBObject.ObjectClosed Event handler during Database.ObjectModified, given that the DBObject is already open.

2.)  If not, the only logical (dependable?) other idea I have is to store the ObjectIds to ObjectIdCollection during the Database.ObjectModified Event, and then attempt to 'act' during one of the Editor.PointFilter, or Editor.PointMonitor Events.  *not sure*
"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: Database.ObjectModified Event
« Reply #10 on: December 10, 2012, 10:06:49 AM »
What I've used is to keep an ObjectIdCollection of modified Objects I need to act on, then do so when the Editor's EnteringQuiescentState event fires.

BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #11 on: December 10, 2012, 10:09:25 AM »
What I've used is to keep an ObjectIdCollection of modified Objects I need to act on, then do so when the Editor's EnteringQuiescentState event fires.

At least I was able to get in the correct vicinity on my own, thanks for the information, Jeff (as always)
"How we think determines what we do, and what we do determines what we get."

BillZndl

  • Guest
Re: Database.ObjectModified Event
« Reply #12 on: December 10, 2012, 03:29:17 PM »
What I've used is to keep an ObjectIdCollection of modified Objects I need to act on, then do so when the Editor's EnteringQuiescentState event fires.

At least I was able to get in the correct vicinity on my own, thanks for the information, Jeff (as always)

Gives my confidence a boost also. Thanks!  :-D

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Database.ObjectModified Event
« Reply #13 on: December 10, 2012, 03:46:40 PM »
I am still not following completely on why does it have to be changed during a modified event rather than doing it during insertion or creation.
 
Are you trying to keep people from modifying a entity or during  modifying set all properties?

BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #14 on: December 10, 2012, 04:12:46 PM »
I am still not following completely on why does it have to be changed during a modified event rather than doing it during insertion or creation.
 
Are you trying to keep people from modifying a entity or during  modifying set all properties?

Perhaps I can clarify... I don't need to do anything during Database.ObjectModified per-se, what I do need to do is to modify specific entity types if they're modified by the user, specifically without depending on a Command Event (i.e., a user selects an MLeader and changes it's layer via Properties Palette).

When doing this, there are only two Database Events that are raised, ObjectOpenedForModify, and ObjectModified... Since I cannot effectively employ UpgradeOpen() within ObjectModified (as the DBObject is no yet Closed), I am forced to store the desired ObjectIds to an ObjectIdCollection, then handle them after the fact.

As I am sure most companies do, we have different text hights/styles (Small, Medium, Large, etc.) and we place them each on specific layers. I often copy a label and manually place it on another layer... It's at this point that I want my plug-in to automagically correct the necessary 'standards' for that entity type when I change it's layer (based upon my XML settings for that particular layer), without the need for running a supplementary custom Command, let alone the Standards Command prior to drawing close.

This would allow for me to catch/filter/enforce these pseudo-annotation standards on the fly, including vanilla, LISP Commands, etc., and further, easily allow me to quickly customize a new 'standard' for each Client as needed, as the XML settings are loaded via valid FindFile() result.

I've got EnteringQuiescentState working to a point, but need more time to work out how to better manage the ObjectIdCollection handling to ensure that handled ObjectIds are in fact removed properly... Still working through the logic (on my part)... Checking for Contains(id), etc., and wanting to compare EnteringQuiescentState to ObjectClosed at entity level (for my own edification, and learning purposes), etc, etc..
« Last Edit: December 10, 2012, 04:45:12 PM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #15 on: December 12, 2012, 10:38:25 AM »
So I've been testing the EnteringQuiescentState approach, and while it works, it's still not 'instantaneous' when one manually makes changes via Properties Palette... There's a delay, until one hits Esc, or click, windows, etc..

I tried looking for alternative Events, and one that came to mind is when DocumentLockModeChangedEventArgs.CurrentMode == DocumentLockMode.NotLocked, but I suspect that there may be some issues with that.

First issue that comes to mind, is attempting to Lock the Document, as this would raise the DocumentLockModeChanged Event again... So I would need to set a bool Property or Field such that the leading if statement would first check for this before continuing... But that still leaves room for an eLockChangeInProgress Exception.

Does anyone have another suggestion(s), in order for me to manipulate the ObjectIds following Database.ObjectModified Event?
"How we think determines what we do, and what we do determines what we get."

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Database.ObjectModified Event
« Reply #16 on: December 12, 2012, 11:47:58 AM »
I have never done testing and just guessing that it would maybe be too resource heavy but could maybe use ObjectOverrule and handle with Close?

TheMaster

  • Guest
Re: Database.ObjectModified Event
« Reply #17 on: December 12, 2012, 09:07:34 PM »
So I've been testing the EnteringQuiescentState approach, and while it works, it's still not 'instantaneous' when one manually makes changes via Properties Palette... There's a delay, until one hits Esc, or click, windows, etc..

I tried looking for alternative Events, and one that came to mind is when DocumentLockModeChangedEventArgs.CurrentMode == DocumentLockMode.NotLocked, but I suspect that there may be some issues with that.

First issue that comes to mind, is attempting to Lock the Document, as this would raise the DocumentLockModeChanged Event again... So I would need to set a bool Property or Field such that the leading if statement would first check for this before continuing... But that still leaves room for an eLockChangeInProgress Exception.

Does anyone have another suggestion(s), in order for me to manipulate the ObjectIds following Database.ObjectModified Event?

Trying to carry the methods used in LISP or VBA over to .NET might work in some cases, but usually introduces its own set of problems, and still suffers from the same limitations you had in the previous implementation.

From the Close() override of an ObjectOverrule, you can modify the object.

If someone here has access to it, feel free to post a copy of my Overrule sample that shows exactly how that can be done (I'd post it myself but it'll take some time for me to find the original that has long since been modified for publication elsewhere).



BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #18 on: December 13, 2012, 09:14:41 AM »
Trying to carry the methods used in LISP or VBA over to .NET might work in some cases, but usually introduces its own set of problems, and still suffers from the same limitations you had in the previous implementation.

Perhaps poorly, that's actually what I am attempting to do here (leave behind my LISP mindset, and elevate my logic to that of .NET development)... Something as you can see I have not yet mastered.

From the Close() override of an ObjectOverrule, you can modify the object.

If someone here has access to it, feel free to post a copy of my Overrule sample that shows exactly how that can be done (I'd post it myself but it'll take some time for me to find the original that has long since been modified for publication elsewhere).

You are kind to offer continued guidance to, not just me, but the AutoCAD development community in general... Thank you, Tony.



In a quick search here for your OverruleSample.zip (previously available from your site here, according to this post). I even found where Kean lauded your comments here... I am however, still unable to find your Overrule Sampe to download and study, even with Wayback Machine... Perhaps I'll ask Jeff H for it:-)
"How we think determines what we do, and what we do determines what we get."

TheMaster

  • Guest
Re: Database.ObjectModified Event
« Reply #19 on: December 13, 2012, 11:43:05 PM »
Attached is one of the samples (I don't know if this was included in the copy I distributed), which shows how to lock the layer of all block references.
« Last Edit: December 13, 2012, 11:56:29 PM by TT »

BlackBox

  • King Gator
  • Posts: 3770
Re: Database.ObjectModified Event
« Reply #20 on: December 14, 2012, 10:12:53 AM »
Attached is one of the samples (I don't know if this was included in the copy I distributed), which shows how to lock the layer of all block references.

Thank you, Tony.
"How we think determines what we do, and what we do determines what we get."