Author Topic: Third Routine - Working Progress  (Read 12204 times)

0 Members and 1 Guest are viewing this topic.

TheMaster

  • Guest
Re: Third Routine - Working Progress
« Reply #30 on: February 07, 2013, 11:37:16 PM »
Tony & Kean, when I saw that post my reaction was that removing xdata this way is an awful solution. If the xdata is not wanted in the copy, then it should not be cloned in the first place. But I don't know off the top of my head how much access you have to cloning operations from the managed API, so I said nothing.

Hi Owen.  There's a few ways to deal with cloning in the managed API, but in the case of OFFSET, I don't think there's any objects being cloned, just the xdata (and probably xdictionary).


owenwengerd

  • Bull Frog
  • Posts: 451
Re: Third Routine - Working Progress
« Reply #31 on: February 08, 2013, 12:01:03 AM »
Upon reflection, I think you're right Tony. There is AcDbCurve::getOffsetCurves(), which would be the logical way to generate the new entity. If xdata is being copied, I wonder if it's done by getOffsetCurves() or by the OFFSET command. If the latter, then Kean's solution doesn't seem so awful after all.

Kean

  • Newt
  • Posts: 48
Re: Third Routine - Working Progress
« Reply #32 on: February 08, 2013, 04:11:22 AM »
I don't bother to visit often, but whenever I do and see code, there's always something that sticks out like a sore thumb. :laugh:

Feel free to post a comment or drop me an email when you see such issues. I appreciate the feedback, especially when it's given politely.

I like your implementation - thanks for sharing it. I choose to structure my code samples more linearly, as they're intended to demonstrate how to do certain things inside AutoCAD. I'd absolutely agree that this kind of abstraction is a good thing, architecturally-speaking, but it unfortunately tends to make it harder to follow for people who are coming to grips with an API (more advanced readers will pick out what they need, in any case). Nevertheless - as I've said - I do like your implementation.

The core issue about having command reactors in place on an ongoing basis is well taken... I'm in any case considering an alternative approach that's a bit more generic - I'll try to post something next week.

Kean

bchapman

  • Guest
Re: Third Routine - Working Progress
« Reply #33 on: February 08, 2013, 12:26:26 PM »
Like I said... the first thing programmers will tell me is go back to the basics lol.... couldn't resist could ya

Knowing the basics of object-oriented programming (classes,methods, properties, static/instance objects, exceptions and handling, and to a lesser extent things like inheritance, abstract/sealed/override) are essential.  Its boring, and repetitive, and takes a lot of work to get it straight, but like most things along those lines the payoff is worth it.  Trying to back into the subject through AutoCAD will raise a lot of questions of "Why do that?" or "Thats pretty vague", or "I don't understand when you say XXXX".  Like when you are asking why define this, then redefine as that, then redefine as something else - this may simply be a matter of a line being an entity being an object, but an object not necessarily being an entity, which is not necessarily a line (inheritance).

Plus, the basics are common across a lot of different samples in VB.NET, C#, C++, along with the host of support namespaces in dotNET like System.XML and System.Data.  A strong base allows you to figure out how to implement somethng even if its not exactly what you are looking for.

TheMaster

  • Guest
Re: Third Routine - Working Progress
« Reply #34 on: February 08, 2013, 08:04:06 PM »
Upon reflection, I think you're right Tony. There is AcDbCurve::getOffsetCurves(), which would be the logical way to generate the new entity. If xdata is being copied, I wonder if it's done by getOffsetCurves() or by the OFFSET command. If the latter, then Kean's solution doesn't seem so awful after all.

Hi Owen, there's nothing 'awful' about Kean's solution. But I took exception to his having commandWillStart, and commandEnded/Failed/Cancelled notifications running full-time because it isn't necessary. If you search ADN, you'll find a code sample written by Cyrille Fauvel, showing correct and efficient use of reactors (in native ObjectARX/C++), where he goes to great lengths to demonstrate how to avoid having reactors running when not absolutely necessary, including the scenario involving command reactors. The concepts demonstrated in his sample apply equally to managed events (that are merely wrappers around native reactor notifications), and I consider it required reading for anyone using either native or managed ObjectARX.

Kean's solution is actually one that follows a very familar and well-known pattern (collecting ObjectIds from a reactor notification where the notifying object cannot be modified, and then at the end of the command, opening the collected ids and operating on them). That pattern has for a very long time, been the standard advice that ADN support techs and others at Autodesk have suggested folks use to solve a class of problems like the one Kean's solution solves belongs to. It is nothing new, and certainly not something germain to Kean's solution.

However that pattern and approach is in my opinion, a horrible kludge, because it requires you to collect ObjectIds and then after the referenced objects have already been closed, reopen them again to do what must be done.

The solution I show that uses an Overrule to solve the same problem, is in my opinion, infinitely better, because it doesn't require you to collect ObjectIds or even re-open the objects to do what must be done. That's because from the Close() notification of an ObjectOverrule, you can modify the notifying object without limitation. I don't think anyone can argue that it isn't a preferable way to solve the problem.

The solution I show and Kean's solution are similar in that both require command begin/end notification. They differ in how the affected objects are modified, and in the fact that my solution was built using a lot of existing, reusable classes that I've used to solve similar problems in the past.

TheMaster

  • Guest
Re: Third Routine - Working Progress
« Reply #35 on: February 10, 2013, 04:42:21 PM »
I posted an older version of the class below in the above post (the more recent version has dependencies on other code that I would've had to remove). There is a bug in that version that was fixed in later versions, and if you're going to adopt it, then you need to either fix the bug or use the version below, which has the bug fixed already. The bug only happens if a transparent command is started in the command that's being watched, which causes the end-command notification to be sent prematurely.

Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Autodesk.AutoCAD.DatabaseServices;
  6. using Autodesk.AutoCAD.Runtime;
  7. using System.ComponentModel;
  8.  
  9. namespace Autodesk.AutoCAD.ApplicationServices.MyExtensions
  10. {
  11.  
  12.    /// <summary>
  13.    /// Get notified about the start and end of certain
  14.    /// commands, without the need for full-time handling
  15.    /// of end-command events;
  16.    /// </summary>
  17.  
  18.    public abstract class CommandObserver : IDisposable
  19.    {
  20.       bool disposed = false;
  21.       Document doc = null;
  22.       bool handled = false;
  23.       string current = null;
  24.  
  25.       public CommandObserver( Document doc )
  26.       {
  27.          if( doc == null )
  28.             throw new ArgumentNullException( "doc" );
  29.          this.doc = doc;
  30.          this.doc.CommandWillStart += commandWillStart;
  31.       }
  32.  
  33.       public enum State
  34.       {
  35.          Starting = 0,
  36.          Ended = 1,
  37.          Cancelled = 2,
  38.          Failed = 3
  39.       }
  40.  
  41.       public Document Document
  42.       {
  43.          get
  44.          {
  45.             return this.doc;
  46.          }
  47.       }
  48.  
  49.       void commandWillStart( object sender, CommandEventArgs e )
  50.       {
  51.          if( OnCommandStarting( e.GlobalCommandName ) )
  52.          {
  53.             current = e.GlobalCommandName;
  54.             AddEndHandlers();
  55.          }
  56.       }
  57.  
  58.       void AddEndHandlers()
  59.       {
  60.          if( !this.handled )
  61.          {
  62.             doc.CommandEnded += doc_CommandEnded;
  63.             doc.CommandFailed += doc_CommandFailed;
  64.             doc.CommandCancelled += doc_CommandCancelled;
  65.             this.handled = true;
  66.          }
  67.       }
  68.  
  69.       void RemoveEndHandlers()
  70.       {
  71.          if( this.handled )
  72.          {
  73.             doc.CommandEnded -= doc_CommandEnded;
  74.             doc.CommandFailed -= doc_CommandFailed;
  75.             doc.CommandCancelled -= doc_CommandCancelled;
  76.             this.handled = false;
  77.             this.current = null;
  78.          }
  79.       }
  80.  
  81.       /// Overrides should return true to be notified
  82.       /// when a command ends (otherwise, there is no
  83.       /// end-of-command notification).
  84.  
  85.       protected virtual bool OnCommandStarting( string name )
  86.       {
  87.          return false;
  88.       }
  89.  
  90.       protected virtual void OnCommandEnded( string name, State state )
  91.       {
  92.       }
  93.  
  94.       void doc_CommandCancelled( object sender, CommandEventArgs e )
  95.       {
  96.          if( e.GlobalCommandName == current )
  97.          {
  98.             RemoveEndHandlers();
  99.             OnCommandEnded( current, State.Cancelled );
  100.          }
  101.       }
  102.  
  103.       void doc_CommandFailed( object sender, CommandEventArgs e )
  104.       {
  105.          if( e.GlobalCommandName == current )
  106.          {
  107.             RemoveEndHandlers();
  108.             OnCommandEnded( current, State.Failed );
  109.          }
  110.       }
  111.  
  112.       void doc_CommandEnded( object sender, CommandEventArgs e )
  113.       {
  114.          if( e.GlobalCommandName == current )
  115.          {
  116.             RemoveEndHandlers();
  117.             OnCommandEnded( current, State.Ended );
  118.          }
  119.       }
  120.  
  121.       protected virtual void Dispose( bool disposing )
  122.       {
  123.          if( !disposed )
  124.          {
  125.             doc.CommandWillStart -= this.commandWillStart;
  126.             RemoveEndHandlers();
  127.             disposed = true;
  128.          }
  129.       }
  130.  
  131.       public void Dispose()
  132.       {
  133.          Dispose( true );
  134.       }
  135.    }
  136.  
  137.  

« Last Edit: February 10, 2013, 04:54:40 PM by TT »

TheMaster

  • Guest
Re: Third Routine - Working Progress
« Reply #36 on: February 10, 2013, 04:55:02 PM »
(continued...)

That version is about 5 years old, and has come a long way since then. Just to show how much more involved it became in order to support efficient use of Overrules, here is the current working version pasted directly from the source code (it isn't going to work as-is because the dependencies aren't included - sorry).

Code - C#: [Select]
  1.  
  2. [DefaultBindingProperty( focusedProperty )]
  3. public abstract class CommandObserver : Switchable, INotifyPropertyChanged
  4. {
  5.    const string focusedProperty = "Focused";
  6.    const string activeProperty = "IsActive";
  7.    const string lispName = "*LISP*";
  8.    Document doc = null;
  9.    DocumentCollection docs = Application.DocumentManager;
  10.    bool handled = false;
  11.    string current = null;
  12.    string nested = null;
  13.    State state = State.None;
  14.    bool ignoreLisp = false;
  15.  
  16.    public CommandObserver( Document doc, bool enabled = true )
  17.       : base( false )
  18.    {
  19.       if( doc == null )
  20.          throw new ArgumentNullException( "doc" );
  21.       this.doc = doc;
  22.       base.Enabled = enabled;
  23.    }
  24.  
  25.    public enum Status
  26.    {
  27.       Starting = 0,
  28.       Ended = 1,
  29.       Cancelled = 2,
  30.       Failed = 3
  31.    }
  32.  
  33.    [Flags]
  34.    public enum State
  35.    {
  36.       None = 0,
  37.  
  38.       /// <summary>
  39.       /// The observed command has been
  40.       /// started and has not yet ended.
  41.       /// </summary>
  42.       Active = 1,
  43.  
  44.       /// <summary>
  45.       /// The observed command is active and
  46.       /// is in use in the active document.
  47.       /// </summary>
  48.       Focused = 2,
  49.  
  50.       /// <summary>
  51.       /// The observed command is suspended while
  52.       /// a transparently-issued command or LISP
  53.       /// expression is in progress.
  54.       /// </summary>
  55.       Modeless = 4,
  56.  
  57.       /// <summary>
  58.       /// The document in which an active observed
  59.       /// command was started, is currently not the
  60.       /// active document.
  61.       /// </summary>
  62.       Document = 8,
  63.  
  64.       /// <summary>
  65.       /// The observed command is suspended while
  66.       /// a LISP expression is being evaluated.
  67.       /// </summary>
  68.       Lisp = 16
  69.    }
  70.  
  71.    public Document Document
  72.    {
  73.       get
  74.       {
  75.          return this.doc;
  76.       }
  77.    }
  78.  
  79.    public State CurrentState
  80.    {
  81.       get
  82.       {
  83.          return state;
  84.       }
  85.    }
  86.  
  87.    /// <summary>
  88.    ///
  89.    /// True = the observed command has started, the Document
  90.    /// in which the observed command was started is active,
  91.    /// and the observed command is not currently suspended
  92.    /// while another transparently-issued command or LISP
  93.    /// expression is active.
  94.    ///
  95.    /// This property can change between the points when an
  96.    /// observed command starts and ends, depending on if
  97.    /// a transparently-issued command is in-progress, LISP
  98.    /// is running, and if the document in which the observed
  99.    /// command was started is currently active.
  100.    ///
  101.    /// </summary>
  102.  
  103.    [Bindable( true )]
  104.    public bool Focused
  105.    {
  106.       get
  107.       {
  108.          return state.HasFlag( State.Focused );
  109.          // return this.doc.IsActive && this.current != null && this.nested == null;
  110.       }
  111.    }
  112.  
  113.    /// <summary>
  114.    /// True = An observed command was started, but has not yet
  115.    /// ended. The command may not be focused (because the document
  116.    /// is not the active document, or because the observed command
  117.    /// was interrupted by another currently-active command or LISP
  118.    /// function that was issued transparently).
  119.    ///
  120.    /// Unlike the Focused property, this property's value remains
  121.    /// true between the point where an observed command is started
  122.    /// and the point where it ends.
  123.    ///
  124.    /// </summary>
  125.  
  126.    [Bindable( true )]
  127.    public bool IsActive
  128.    {
  129.       get
  130.       {
  131.          return this.current != null;
  132.       }
  133.    }
  134.  
  135.    /// <summary>
  136.    ///
  137.    /// The active observed command, or an
  138.    /// empty string if no observed command
  139.    /// is active.
  140.    ///
  141.    /// </summary>
  142.  
  143.    [Bindable( true )]
  144.    public string Current
  145.    {
  146.       get
  147.       {
  148.          return this.current ?? string.Empty;
  149.       }
  150.    }
  151.  
  152.    /// <summary>
  153.    ///
  154.    /// The name of the transparently-issued command
  155.    /// that has interrupted the observed command, while
  156.    /// the observed command is interrupted.
  157.    ///
  158.    /// The value of this property is not necessarily the
  159.    /// name of a currently active, transparently-issued
  160.    /// command. The names of nested transparently-issued
  161.    /// commands or LISP expressions that do not change
  162.    /// the Focused state of the observed command are not
  163.    /// returned in this property.
  164.    ///
  165.    /// A 'nested' transparently-issued command is a command
  166.    /// that was transparently issued while another transparently-
  167.    /// issued command was in progress.
  168.    ///
  169.    /// If the observed command was interrupted by a LISP
  170.    /// expression, the value of this property will be the
  171.    /// value of the LispName property
  172.    ///
  173.    /// </summary>
  174.  
  175.    public string Nested
  176.    {
  177.       get
  178.       {
  179.          return this.nested ?? string.Empty;
  180.       }
  181.    }
  182.  
  183.    /////////////////////////////////////////////////////////////
  184.    /// Overridables:
  185.  
  186.    /// <summary>
  187.    ///
  188.    /// <warning>
  189.    /// It is critically-necessary for overrides in
  190.    /// all derived types to supermessage this.
  191.    /// </warning>
  192.    ///
  193.    /// Called when the instance is enabled or disabled
  194.    /// by setting the Enabled property.
  195.    ///
  196.    /// When the instance is not enabled, all command-
  197.    /// related activity, including starting of commands,
  198.    /// is disabled.
  199.    ///
  200.    /// </summary>
  201.  
  202.    protected override void OnEnabledChanged( bool value )
  203.    {
  204.       if( value )
  205.       {
  206.          this.doc.CommandWillStart += commandWillStart;
  207.       }
  208.       else
  209.       {
  210.          this.doc.CommandWillStart -= commandWillStart;
  211.          RemoveHandlers();
  212.       }
  213.       NotifyPropertyChanged( "Enabled" );
  214.    }
  215.  
  216.    /// <summary>
  217.    ///
  218.    /// Indicates that a command is starting. overrides
  219.    /// should return true to indicate if the command
  220.    /// that is starting should be observed.
  221.    ///
  222.    /// If false is returned, the command's state is not
  223.    /// observed and all other notifications, including
  224.    /// when the command ends are not sent.
  225.    ///
  226.    /// </summary>
  227.    /// <param name="name">The global name of the command that is starting</param>
  228.    /// <returns>A value indicating if the command should be observed</returns>
  229.  
  230.    protected abstract bool OnCommandStarting( string name );
  231.  
  232.    /// <summary>
  233.    /// Indicates that an observed command has ended.
  234.    /// </summary>
  235.    /// <param name="name">The name of the command that has ended</param>
  236.    /// <param name="status">A value indicating how the command ended</param>
  237.  
  238.    protected virtual void OnCommandEnded( string name, Status status )
  239.    {
  240.    }
  241.  
  242.    /// <summary>
  243.    ///
  244.    /// Called when the 'focused' state of an observed
  245.    /// command changes.
  246.    ///
  247.    /// An observed command is in the focused state
  248.    /// when all of the following conditions are true:
  249.    ///
  250.    ///   - The observed command has been started,
  251.    ///     and has not yet ended.
  252.    ///  
  253.    ///   - The document in which the observed
  254.    ///     command was started is the active
  255.    ///     document.
  256.    ///  
  257.    ///   - The observed command is not currently
  258.    ///     suspended while another transparently-
  259.    ///     issued command or LISP expression is
  260.    ///     active or in-progress.
  261.    ///  
  262.    /// OnFocusdChanged() is called when a change
  263.    /// in any of the above conditions causes the
  264.    /// focused state of an observed command to
  265.    /// change.
  266.    ///
  267.    /// Specifically:
  268.    ///
  269.    /// - When the observed comand starts and ends.
  270.    ///
  271.    /// - When a transparent command starts or ends
  272.    ///   while the observed command is in progress,
  273.    ///   but not when additional commands are issued
  274.    ///   transparently while a transparently-issued
  275.    ///   command is active.
  276.    ///  
  277.    /// - When the document in which an observed command
  278.    ///   was started is activated or deactivated, while
  279.    ///   no transparently-issued command is active.
  280.    ///
  281.    ///   Nested, transparently-issued commands that
  282.    ///   are issued while other transparently-issued
  283.    ///   commands are active, do not alter the focused
  284.    ///   state of the observed command.
  285.    ///  
  286.    ///   Changes to the active document that occur
  287.    ///   while a transparently-issued command is in
  288.    ///   progress, do not alter the focused state of
  289.    ///   the observed command.
  290.    ///  
  291.    ///   observed is the name of the observed command.
  292.    ///  
  293.    ///   The focused parameter indicates if the observed
  294.    ///   command has become focused, as it is defined
  295.    ///   above. True means the command has entered the
  296.    ///   focused state. False indicates the command has
  297.    ///   left the focused state.
  298.    ///  
  299.    ///   state indicates the condition(s) that changed,
  300.    ///   resulting in a change to the the focused state,
  301.    ///   as follows:
  302.    ///  
  303.    ///   State.Active: The observed command started or ended
  304.    ///  
  305.    ///   State.Modeless: The observed command was interrupted
  306.    ///   when a transparently-issued command was started, or
  307.    ///   was resumed when a transparently-issued command ended.
  308.    ///  
  309.    ///   State.Lisp: The observed command was interrupted
  310.    ///   when a LISP expression was evaluated, or was resumed
  311.    ///   when the LISP expression's evaluation is completed.
  312.    ///   When this flag is present, the Modeless flag is also
  313.    ///   present.
  314.    ///  
  315.    ///   State.Document: The active state of the document in
  316.    ///   which the observed command was started has changed.
  317.    ///
  318.    /// </summary>
  319.  
  320.    protected virtual void OnFocusChanged( string observed, bool focused, State state )
  321.    {
  322.    }
  323.  
  324.    /// <summary>
  325.    ///
  326.    /// Called when an observed command that is currently
  327.    /// active, is suspended or interrupted as a result of
  328.    /// another command having been issued transparently,
  329.    /// or by evaluation of LISP.
  330.    ///
  331.    /// nested is the name of the interrupting, transparently-
  332.    /// issued command that is starting. If the interruption
  333.    /// is a result of a LISP expression, the value of this
  334.    /// parameter will be the value of the LispName property.
  335.    ///
  336.    /// </summary>
  337.  
  338.    protected virtual void OnSuspend( string current, string nested )
  339.    {
  340.    }
  341.  
  342.    /// <summary>
  343.    ///
  344.    /// Called when an observed command that is currently
  345.    /// in-progress and has been suspended or interrupted
  346.    /// by the use of a transparent command or LISP, is
  347.    /// resumed as a result of the transparent command or
  348.    /// LISP ending.
  349.    ///
  350.    /// The first argument is the name of the active observed
  351.    /// command.
  352.    ///
  353.    /// The second argument is the name of the transparently-
  354.    /// issued command that is ending, or the value of the
  355.    /// LispName property if the interruption was triggered
  356.    /// by evalution of a LISP expression.
  357.    ///
  358.    /// </summary>
  359.  
  360.    protected virtual void OnResume( string current, string nested )
  361.    {
  362.    }
  363.  
  364.    /// <summary>
  365.    ///
  366.    /// Called when a document containing the Focused, observed
  367.    /// command is deactivated, as a result of a change to the
  368.    /// active document. This notification is sent only if the
  369.    /// observed command is focused. If the observed command is
  370.    /// not currently focused (e.g., the command is suspended
  371.    /// while one or more transparently-issued commands are in
  372.    /// progress) the notification is not sent.
  373.    ///
  374.    /// Calls to this notification are followed by a call to
  375.    /// the OnDocumentActivated() method when the document is
  376.    /// subsequently activated again.
  377.    ///
  378.    /// </summary>
  379.  
  380.    protected virtual void OnDocumentDeactivated( string current )
  381.    {
  382.    }
  383.  
  384.    /// <summary>
  385.    ///
  386.    /// Called when a non-active document containing a Focused,
  387.    /// observed command is activated. This notification is sent
  388.    /// only if the observed command is focused. If the observed
  389.    /// command is not currently focused (e.g., the command is
  390.    /// suspended while one or more transparently-issued commands
  391.    /// are in progress) the notification is not sent.
  392.    ///
  393.    /// Calls to this notification are always preceded by a call
  394.    /// to the OnDocumentDeactivated() method.
  395.    ///
  396.    /// </summary>
  397.  
  398.    protected virtual void OnDocumentActivated( string current )
  399.    {
  400.    }
  401.  
  402.    /////////////////////////////////////////////////////////////
  403.    /// Non-public implementation
  404.  
  405.    void SetState( State flags, bool value = true )
  406.    {
  407.       if( value )
  408.          state |= flags;
  409.       else
  410.          state &= ~flags;
  411.    }
  412.  
  413.    void commandWillStart( object sender, CommandEventArgs e )
  414.    {
  415.       OnStarting( e.GlobalCommandName );
  416.    }
  417.  
  418.    void OnStarting( string name )
  419.    {
  420.       if( current == null ) // ! state.HasFlag( State.Active ) )
  421.       {
  422.          if( OnCommandStarting( name ) )
  423.          {
  424.             current = name;
  425.             AddHandlers();
  426.             state = State.Active;
  427.             StateChanged( true, State.Active );
  428.          }
  429.       }
  430.       else if( nested == null ) // ! state.HasFlag( State.Modeless ) )
  431.       {
  432.          nested = name;
  433.          OnSuspend( current, nested );
  434.          State changing = GetModelessState( name );
  435.          SetState( changing );
  436.          StateChanged( false, changing );
  437.       }
  438.    }
  439.  
  440.    void OnEnding( string name, Status status )
  441.    {
  442.       if( name == current )
  443.       {
  444.          try
  445.          {
  446.             RemoveHandlers();
  447.             StateChanged( false, State.Active );
  448.             state = State.None;
  449.             OnCommandEnded( name, status );
  450.          }
  451.          finally
  452.          {
  453.             current = null;
  454.          }
  455.       }
  456.       else if( name == nested )
  457.       {
  458.          try
  459.          {
  460.             State changing = GetModelessState( name );
  461.             SetState( changing, false );
  462.             StateChanged( true, changing );
  463.             OnResume( current, name );
  464.          }
  465.          finally
  466.          {
  467.             nested = null;
  468.          }
  469.       }
  470.    }
  471.  
  472.    State GetModelessState( string name )
  473.    {
  474.       return name == lispName ? State.Modeless | State.Lisp : State.Modeless;
  475.    }
  476.  
  477.    void documentActivated( object sender, DocumentCollectionEventArgs e )
  478.    {
  479.       if( e.Document == this.doc )
  480.       {
  481.          if( nested == null ) // ( state & ~ State.Document ) == State.Active )
  482.          {
  483.             OnDocumentActivated( current );
  484.             StateChanged( true, State.Document );
  485.          }
  486.          SetState( State.Document, false );
  487.       }
  488.    }
  489.  
  490.    void documentToBeDeactivated( object sender, DocumentCollectionEventArgs e )
  491.    {
  492.       if( e.Document == this.doc )
  493.       {
  494.          if( nested == null ) // state == State.Active ) // nested == null )
  495.          {
  496.             OnDocumentDeactivated( current );
  497.             StateChanged( false, State.Document );
  498.          }
  499.          SetState( State.Document );
  500.       }
  501.    }
  502.  
  503.    void StateChanged( bool focused, State changed )
  504.    {
  505.       SetState( State.Focused, focused );
  506.       OnFocusChanged( this.current, focused, changed );
  507.       if( PropertyChanged != null )
  508.       {
  509.          NotifyPropertyChanged( focusedProperty );
  510.          if( changed == State.Active )
  511.             NotifyPropertyChanged( activeProperty );
  512.       }
  513.       MyUtils.WriteDebugMessage( "*** OnFocusedChanged( {0}, {1}, {2} ) ***",
  514.          current, focused, changed );
  515.    }
  516.  
  517.    void NotifyPropertyChanged( string name )
  518.    {
  519.       if( PropertyChanged != null )
  520.          PropertyChanged( this, new PropertyChangedEventArgs( name ) );
  521.    }
  522.  
  523.    void AddHandlers()
  524.    {
  525.       if( !this.handled )
  526.       {
  527.          this.handled = true;
  528.          doc.CommandEnded += commandEnded;
  529.          doc.CommandFailed += commandFailed;
  530.          doc.CommandCancelled += commandCancelled;
  531.          docs.DocumentActivated += documentActivated;
  532.          docs.DocumentToBeDeactivated += documentToBeDeactivated;
  533.          if( ! ignoreLisp )
  534.          {
  535.             doc.LispWillStart += lispWillStart;
  536.             doc.LispEnded += lispEnded;
  537.             doc.LispCancelled += lispCancelled;
  538.          }
  539.       }
  540.    }
  541.  
  542.    void RemoveHandlers()
  543.    {
  544.       if( this.handled )
  545.       {
  546.          this.handled = false;
  547.          doc.CommandEnded -= commandEnded;
  548.          doc.CommandFailed -= commandFailed;
  549.          doc.CommandCancelled -= commandCancelled;
  550.          docs.DocumentToBeDeactivated -= documentToBeDeactivated;
  551.          docs.DocumentActivated -= documentActivated;
  552.          if( ! ignoreLisp )
  553.          {
  554.             doc.LispWillStart -= lispWillStart;
  555.             doc.LispEnded -= lispEnded;
  556.             doc.LispCancelled -= lispCancelled;
  557.          }
  558.       }
  559.    }
  560.  
  561.    public bool IgnoreLisp
  562.    {
  563.       get
  564.       {
  565.          return ignoreLisp;
  566.       }
  567.       set
  568.       {
  569.          ignoreLisp = value;
  570.       }
  571.    }
  572.  
  573.    public static string LispName
  574.    {
  575.       get
  576.       {
  577.          return lispName;
  578.       }
  579.    }
  580.  
  581.    public static bool IsLisp( string name )
  582.    {
  583.       return name == lispName;
  584.    }
  585.  
  586.    void lispWillStart( object sender, LispWillStartEventArgs e )
  587.    {
  588.       OnStarting( lispName );
  589.    }
  590.  
  591.    void lispCancelled( object sender, EventArgs e )
  592.    {
  593.       OnEnding( lispName, Status.Cancelled );
  594.    }
  595.  
  596.    void lispEnded( object sender, EventArgs e )
  597.    {
  598.       OnEnding( lispName, Status.Ended );
  599.    }
  600.  
  601.    void commandCancelled( object sender, CommandEventArgs e )
  602.    {
  603.       OnEnding( e.GlobalCommandName, Status.Cancelled );
  604.    }
  605.  
  606.    void commandFailed( object sender, CommandEventArgs e )
  607.    {
  608.       OnEnding( e.GlobalCommandName, Status.Failed );
  609.    }
  610.  
  611.    void commandEnded( object sender, CommandEventArgs e )
  612.    {
  613.       OnEnding( e.GlobalCommandName, Status.Ended );
  614.    }
  615.  
  616.    public event PropertyChangedEventHandler PropertyChanged;
  617. }
  618.  
  619.  
« Last Edit: February 10, 2013, 05:02:28 PM by TT »

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: Third Routine - Working Progress
« Reply #37 on: February 11, 2013, 10:29:44 AM »
Like I said... the first thing programmers will tell me is go back to the basics lol.... couldn't resist could ya

Knowing the basics of object-oriented programming (classes,methods, properties, static/instance objects, exceptions and handling, and to a lesser extent things like inheritance, abstract/sealed/override) are essential.  Its boring, and repetitive, and takes a lot of work to get it straight, but like most things along those lines the payoff is worth it.  Trying to back into the subject through AutoCAD will raise a lot of questions of "Why do that?" or "Thats pretty vague", or "I don't understand when you say XXXX".  Like when you are asking why define this, then redefine as that, then redefine as something else - this may simply be a matter of a line being an entity being an object, but an object not necessarily being an entity, which is not necessarily a line (inheritance).

Plus, the basics are common across a lot of different samples in VB.NET, C#, C++, along with the host of support namespaces in dotNET like System.XML and System.Data.  A strong base allows you to figure out how to implement somethng even if its not exactly what you are looking for.

I'm not a programmer   ;-)
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}