Author Topic: Getting notified when a PaletteSet is hidden/closed  (Read 1290 times)

0 Members and 1 Guest are viewing this topic.

TT

  • Swamp Rat
  • Posts: 826
Getting notified when a PaletteSet is hidden/closed
« on: July 05, 2012, 03:39:44 pm »
This was quickly written and only briefly tested, but appears to work more reliably than the solution shown on Kean's blog.

Code: [Select]
// Original code by Kean walmsley at:
// http://through-the-interface.typepad.com/through_the_interface/2011/12/creating-a-custom-paletteset-class-exposing-a-close-event-inside-autocad-using-net.html

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using System;
 
namespace Autodesk.AutoCAD.Windows
{
  public class PaletteSetWithCloseEvent : PaletteSet
  {
    public PaletteSetWithCloseEvent( string cmd )
      : base( cmd )
    {
      Init();
    }
   
    public PaletteSetWithCloseEvent( string cmd, Guid guid )
      : base( cmd, guid )
    {
      Init();
    }
 
    // Common construction operations. 
    // If you overload the constructor, your overloads
    // should call this method:
   
    void Init()
    {
      this.StateChanged += stateChanged;
    }
   
    // event to be fired on close
 
    public event EventHandler PaletteSetClosed;
   
    // flag indicating if Application.Idle is being handled
   
    bool idleHandled = false;

    void stateChanged( object sender, PaletteSetStateEventArgs e )
    {
      if( ! idleHandled && e.NewState == StateEventIndex.Hide )
      {
        idleHandled = true;
        Application.Idle += onIdle;
      }
      else if( idleHandled && e.NewState == StateEventIndex.Show )
      {
        idleHandled = false;
        Application.Idle -= onIdle;
      }
    }
   
    // If the paletteset is docked/undocked, the idle
    // event should not fire until the entire operation
    // is completed, allowing it to be used to detect
    // if the paletteSet is no longer visible:
   
    void onIdle( object sender, EventArgs e )
    {
      if( ! this.Visible )
        this.OnPaletteSetClosed();
      Application.Idle -= onIdle;
      idleHandled = false;
    }
   
    // If you derive your PaletteSet class from this class (recommended)
    // You can simply override this method rather than handing the
    // PaletteSetClosed event:

    protected virtual void OnPaletteSetClosed()
    {
      if( this.PaletteSetClosed != null )
        this.PaletteSetClosed( this, EventArgs.Empty );
    }
 
  }
}

« Last Edit: July 05, 2012, 06:56:59 pm by TheMaster »

Draftek

  • Swamp Rat
  • Posts: 1498
Re: Getting notified when a PaletteSet is hidden/closed
« Reply #1 on: July 05, 2012, 04:06:03 pm »
Thanks, that might come in handy.
Soli Deo Gloria

TT

  • Swamp Rat
  • Posts: 826
Re: Getting notified when a PaletteSet is hidden/closed
« Reply #2 on: August 13, 2012, 02:06:58 am »
This was quickly written and only briefly tested, but appears to work more reliably than the solution shown on Kean's blog.

Revised to overcome a bug causing the close event to fire when a paletteset's Auto-hide button is clicked and the PaletteSet is rolled up. Also includes a simple test class.

Code - C#: [Select]
  1.  
  2. // PaletteSetWithCloseEvent.cs
  3. // Copyright (c) 2009-2012  Tony Tanzillo
  4.  
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using Autodesk.AutoCAD.ApplicationServices;
  10. using Autodesk.AutoCAD.Runtime;
  11. using Autodesk.AutoCAD.Windows;
  12.  
  13. /// Abstract:
  14. ///
  15. /// This class specializes the Autodesk.AutoCAD.Windows.PaletteSet
  16. /// class, adding a PaletteSetClosed event along with a corresponding
  17. /// overridable virtual method, allowing the PaletteSet and observers
  18. /// of the event to be notified when the PaletteSet is closed.
  19. ///
  20. /// Background:
  21. ///
  22. /// The PaletteSet's StateChanged event fires multiple times when a
  23. /// PaletteSet is docked, undocked, or rolled up when the Auto-hide
  24. /// button is clicked. Because of that, it becomes impossible to use
  25. /// that event directly to tell when a PaletteSet is actually hidden
  26. /// (technically, PaletteSets are never 'closed', when the "x" close
  27. /// button is clicked - rather they are hidden and remain in memory,
  28. /// ready to be made visible again).
  29. ///
  30. /// This class employs a few tricks to overcome this limitation, and
  31. /// provides a new Event and overridable virtual method that signals
  32. /// when the PalletSet is actually closed.
  33. ///
  34. /// You can use this class in lieu of the stock PaletteSet class, if
  35. /// you need to be notified when the PaletteSet is hidden. In all
  36. /// other respects, it behaves exactly the same as its base class.
  37.  
  38. namespace Autodesk.AutoCAD.Windows
  39. {
  40.  
  41.   public class PaletteSetWithCloseEvent : PaletteSet
  42.   {
  43.      bool initialized = false;
  44.      public PaletteSetWithCloseEvent( string showCommand )
  45.         : base( showCommand )
  46.      {
  47.         Init();
  48.      }
  49.  
  50.      public PaletteSetWithCloseEvent( string showCommand, Guid guid )
  51.         : base( showCommand, guid )
  52.      {
  53.         Init();
  54.      }
  55.  
  56.      // Common construction operations.  
  57.      // If you overload the constructor in a derived type,
  58.      // your overload must either supermessage one of the
  59.      // above constructors, or must call this method:
  60.  
  61.      protected void Init()
  62.      {
  63.         if( ! initialized )
  64.         {
  65.            initialized = true;
  66.            this.StateChanged += stateChanged;
  67.         }
  68.      }
  69.  
  70.      // Event to be fired on close.
  71.  
  72.      // Note:
  73.      //
  74.      // If you derive your PaletteSet class from
  75.      // this class, then you should override the
  76.      // OnPaletteSetClosed() virtual method below,
  77.      // rather than handling this event. This event
  78.      // is primarily intended to be used from the
  79.      // outside, rather than from a derived type.
  80.  
  81.      public event EventHandler PaletteSetClosed;
  82.  
  83.      // flag indicating if Application.Idle is being handled
  84.  
  85.      bool idleHandled = false;
  86.  
  87.      // Flag indicating if the PaletteSet was rolled up when
  88.      // the StateChanged event fired:
  89.  
  90.      bool wasRolledUp = false;
  91.  
  92.      void stateChanged( object sender, PaletteSetStateEventArgs e )
  93.      {
  94.         if( ! idleHandled && e.NewState == StateEventIndex.Hide )
  95.         {
  96.            idleHandled = true;
  97.            this.wasRolledUp = base.RolledUp;
  98.            Application.Idle += onIdle;
  99.         }
  100.         else if( idleHandled && e.NewState == StateEventIndex.Show )
  101.         {
  102.            idleHandled = false;
  103.            Application.Idle -= onIdle;
  104.         }
  105.      }
  106.  
  107.      // If the paletteset is docked/undocked or rolled-up,
  108.      // the idle event should not fire until the entire
  109.      // operation is completed, allowing it to be used to
  110.      // detect if the paletteSet is no longer visible:
  111.  
  112.      // [TT] 08-12-12:
  113.      // Revised to deal with auto-hide, which was being
  114.      // mis-interpreted as closing the paletteset.
  115.  
  116.      void onIdle( object sender, EventArgs e )
  117.      {
  118.         Application.Idle -= onIdle;
  119.         idleHandled = false;
  120.         if( ! ( base.Visible || ( wasRolledUp ^ this.RolledUp ) ) )
  121.         {
  122.            this.OnPaletteSetClosed();
  123.         }
  124.      }
  125.  
  126.      // If you derive your PaletteSet class from this class (recommended),
  127.      // your derived class can override this method rather than handing
  128.      // the PaletteSetClosed event:
  129.  
  130.      protected virtual void OnPaletteSetClosed()
  131.      {
  132.         if( this.PaletteSetClosed != null )
  133.            this.PaletteSetClosed( this, EventArgs.Empty );
  134.      }
  135.  
  136.   }
  137. }
  138.  
  139. // MyPaletteSet.cs - simple test case
  140. //
  141. // This simple test case also demonstrates the recommended
  142. // pattern for consuming a PalletSet - by deriving a class from
  143. // it that encapsulates all required functionality.
  144.  
  145. using System;
  146. using System.Collections.Generic;
  147. using System.Linq;
  148. using System.Text;
  149. using Autodesk.AutoCAD.Windows;
  150. using Autodesk.AutoCAD.ApplicationServices;
  151. using Autodesk.AutoCAD.Runtime;
  152.  
  153. namespace PaletteSetWithCloseEventTest
  154. {
  155.   public class MyPaletteSet : PaletteSetWithCloseEvent
  156.   {
  157.      static MyPaletteSet instance = null;
  158.      static Guid guid = new Guid( "{41738157-3080-4015-AB53-3ACF8067C791}" );
  159.      const string showCommand = "MYPALETTESET";
  160.  
  161.      public MyPaletteSet()
  162.         : base( showCommand, guid )
  163.      {
  164.         base.Add( "UserControl", new System.Windows.Forms.UserControl() );
  165.      }
  166.  
  167.      protected override void OnPaletteSetClosed()
  168.      {
  169.         Document doc = Application.DocumentManager.MdiActiveDocument;
  170.         if( doc != null )
  171.         {
  172.            doc.Editor.WriteMessage( "\n*** OnPaletteSetClosed() - Without the kludge  :p ***\n" );
  173.         }
  174.      }
  175.  
  176.      [CommandMethod( showCommand )]
  177.      public static void MyPaletteSetCommand()
  178.      {
  179.         if( instance == null )
  180.            instance = new MyPaletteSet();
  181.         instance.Visible = true;
  182.      }
  183.   }
  184. }
  185.  
  186.  
  187.  
« Last Edit: August 13, 2012, 03:56:31 pm by TT »