Author Topic: Zero Document State and custom tool palettes  (Read 1828 times)

0 Members and 1 Guest are viewing this topic.

Keith Brown

  • Swamp Rat
  • Posts: 585
Zero Document State and custom tool palettes
« on: February 16, 2014, 02:20:38 pm »
I have created some custom tool palettes using the PaletteSet class and discovered that when all documents are closed that the palette remains open and all functions of the palettes are still intact.  This is a behavior that I do not want.  Instead of writing code for each function to determine if the application was in a zero document state I decided to just change the visibility of the palette to false whenever entering this state.  Also when leaving a zero document state I wanted the palette to regain its previous visibility setting.  So if the palette was not visible when entering a zero document state I wanted it to still not be visible when leaving the state and also if it was visible then still be visible.  At first I developed some code in the method that created the palette to handle this situation then I thought that it would be better to just extend the PaletteSet class and use the new class instead of the old one.

In case anyone else runs into a situation like this here is the code that I now use for most of my custom tool palettes.



Hopefully this will save someone some time in the future.

Code - C#: [Select]
  1. // Makes use of the code provided by Tony Tanzilla located at
  2. // http://www.theswamp.org/index.php?topic=42179.msg476706#msg476706
  3. namespace Autodesk.AutoCAD.Windows;
  4. {
  5.    using System;
  6.  
  7.    using Autodesk.AutoCAD.ApplicationServices;
  8.  
  9.    using Application = Autodesk.AutoCAD.ApplicationServices.Core.Application;
  10.  
  11.    /// <summary>
  12.    ///     An enhanced version of the PaletteSet that will insure that the
  13.    ///     visibility of the palette is <see langword="false" /> when the
  14.    ///     application enters a Zero Document State or the current document is
  15.    ///     null. When exiting a Zero Document State or a <see langword="null"/>
  16.    ///     document the palette will regain its previous visibility setting.
  17.    /// </summary>
  18.    public class EnhancedPaletteSet : PaletteSet
  19.    {
  20.        #region Private Fields
  21.  
  22.        /// <summary>
  23.        ///     Determines if the idle event was handled.
  24.        /// </summary>
  25.        private bool _idleHandled;
  26.  
  27.        /// <summary>
  28.        ///     Determines if the class has been initialized.
  29.        /// </summary>
  30.        private bool _initialized;
  31.  
  32.        /// <summary>
  33.        ///     Determines if the palette was rolled up.
  34.        /// </summary>
  35.        private bool _wasRolledUp;
  36.  
  37.  
  38.        /// <summary>
  39.        ///     Stores the previous state of the palette
  40.        /// </summary>
  41.        private bool _wasVisible;
  42.  
  43.        /// <summary>
  44.        ///     Determines if the palette was auto closed.
  45.        /// </summary>
  46.        private bool _autoClosed;
  47.  
  48.        #endregion Private Fields
  49.  
  50.        #region Public Constructors
  51.  
  52.        /// <summary>
  53.        ///     Initializes a new instance of the
  54.        ///     <see cref="EnhancedPaletteSet" /> class.
  55.        /// </summary>
  56.        /// <param name="name">The name.</param>
  57.        /// <param name="cmd">The command.</param>
  58.        /// <param name="toolId">The tool identifier.</param>
  59.        public EnhancedPaletteSet(string name, string cmd, Guid toolId)
  60.            : base(name, cmd, toolId)
  61.        {
  62.            this.Initialize();
  63.        }
  64.  
  65.        /// <summary>
  66.        ///     Initializes a new instance of the
  67.        ///     <see cref="EnhancedPaletteSet" /> class.
  68.        /// </summary>
  69.        /// <param name="name">The name.</param>
  70.        /// <param name="toolId">The tool identifier.</param>
  71.        public EnhancedPaletteSet(string name, Guid toolId)
  72.            : base(name, toolId)
  73.        {
  74.            this.Initialize();
  75.        }
  76.  
  77.        /// <summary>
  78.        ///     Initializes a new instance of the
  79.        ///     <see cref="EnhancedPaletteSet" /> class.
  80.        /// </summary>
  81.        /// <param name="name">The name.</param>
  82.        public EnhancedPaletteSet(string name)
  83.            : base(name)
  84.        {
  85.            this.Initialize();
  86.        }
  87.  
  88.        #endregion Public Constructors
  89.  
  90.        #region Public Events
  91.  
  92.        /// <summary>
  93.        /// Occurs when the palette set is closed by the user.
  94.        /// </summary>
  95.        public event EventHandler PaletteSetClosed;
  96.  
  97.        #endregion Public Events
  98.  
  99.        #region Public Methods
  100.  
  101.        /// <summary>
  102.        ///     Toggles this instance.
  103.        /// </summary>
  104.        public void Toggle()
  105.        {
  106.            this.Visible = !this.Visible;
  107.        }
  108.  
  109.        #endregion Public Methods
  110.  
  111.        #region Protected Methods
  112.  
  113.        /// <summary>
  114.        ///     Called when the palette set is closed If you derive your
  115.        ///     PaletteSet class from this class your derived class can
  116.        ///     <see langword="override"/> this method rather than handling the
  117.        ///     <see cref="PaletteSetClosed"/> event but make sure to call this
  118.        ///     method from the overridden method.
  119.        /// </summary>
  120.        protected virtual void OnPaletteSetClosed()
  121.        {
  122.            if (!this._autoClosed)
  123.            {
  124.                if (this.PaletteSetClosed != null)
  125.                {
  126.                    this.PaletteSetClosed(this, EventArgs.Empty);
  127.                }
  128.            }
  129.  
  130.  
  131.            if (!this._autoClosed)
  132.            {
  133.                this._wasVisible = false;
  134.            }
  135.        }
  136.  
  137.        #endregion Protected Methods
  138.  
  139.        #region Private Methods
  140.  
  141.        /// <summary>
  142.        ///     Handles the OnIdle event of the Application control.
  143.        /// </summary>
  144.        /// <param name="sender">The source of the event.</param>
  145.        /// <param name="e">
  146.        /// The <see cref="System.EventArgs" /> instance containing the event
  147.        /// data.
  148.        /// </param>
  149.        private void Application_OnIdle(object sender, EventArgs e)
  150.        {
  151.            Application.Idle -= this.Application_OnIdle;
  152.            this._idleHandled = false;
  153.            if (!(this.Visible || (this._wasRolledUp ^ this.RolledUp)))
  154.            {
  155.                this.OnPaletteSetClosed();
  156.            }
  157.        }
  158.  
  159.        /// <summary>
  160.        ///     Handles the DocumentActivated event of the DocumentCollection
  161.        ///     control.
  162.        /// </summary>
  163.        /// <param name="sender">The source of the event.</param>
  164.        /// <param name="e">
  165.        /// The
  166.        /// <see cref="Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs" />
  167.        /// instance containing the event data.
  168.        /// </param>
  169.        private void DocumentCollection_DocumentActivated(object sender, DocumentCollectionEventArgs e)
  170.        {
  171.            if (Active.Document == null)
  172.            {
  173.                if (this.Visible || this.RolledUp)
  174.                {
  175.                    this.Visible = false;
  176.                    this._autoClosed = true;
  177.                    this._wasVisible = true;
  178.                }
  179.            }
  180.            else
  181.            {
  182.                if (this._wasVisible)
  183.                {
  184.                    this.Visible = true;
  185.                    this._autoClosed = false;
  186.                }
  187.            }
  188.        }
  189.  
  190.  
  191.        /// <summary>
  192.        ///     If we have exited zero document state or the new document is not
  193.        ///     <see langword="null"/> then this method will execute.
  194.        /// </summary>
  195.        /// <param name="sender">The sender.</param>
  196.        /// <param name="e">
  197.        /// The
  198.        /// <see cref="Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs" />
  199.        /// instance containing the event data.
  200.        /// </param>
  201.        private void DocumentCollection_DocumentCreatedFromZeroDocumentState(object sender, DocumentCollectionEventArgs e)
  202.        {
  203.            var documentCollection = (DocumentCollection)sender;
  204.  
  205.  
  206.            if (documentCollection.Count > 1 && Active.Document != null)
  207.            {
  208.                if (this._wasVisible)
  209.                {
  210.                    this.Visible = true;
  211.                    this._autoClosed = false;
  212.                }
  213.            }
  214.        }
  215.  
  216.  
  217.        /// <summary>
  218.        ///     If in zero document state or if the active document is
  219.        ///     <see langword="null"/> then this method will execute.
  220.        /// </summary>
  221.        /// <param name="sender">The sender.</param>
  222.        /// <param name="e">
  223.        /// The
  224.        /// <see cref="Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs" />
  225.        /// instance containing the event data.
  226.        /// </param>
  227.        private void DocumentCollection_DocumentToBeDestroyedPreventZeroDocumentState(object sender, DocumentCollectionEventArgs e)
  228.        {
  229.            var documentCollection = (DocumentCollection)sender;
  230.  
  231.  
  232.            if (documentCollection.Count == 1 || Active.Document == null)
  233.            {
  234.                if (this.Visible)
  235.                {
  236.                    this.Visible = false;
  237.                    this._wasVisible = true;
  238.                    this._autoClosed = true;
  239.                }
  240.                else
  241.                {
  242.                    this._wasVisible = false;
  243.                }
  244.            }
  245.        }
  246.  
  247.  
  248.        /// <summary>
  249.        ///     Initializes the class. If you overload the construction in a
  250.        ///     derived type, your overload must call one of the above
  251.        ///     constructors or it must call this method.
  252.        /// </summary>
  253.        private void Initialize()
  254.        {
  255.            if (!this._initialized)
  256.            {
  257.                this._initialized = true;
  258.                var documentCollection = Application.DocumentManager;
  259.                documentCollection.DocumentToBeDestroyed += this.DocumentCollection_DocumentToBeDestroyedPreventZeroDocumentState;
  260.                documentCollection.DocumentCreated += this.DocumentCollection_DocumentCreatedFromZeroDocumentState;
  261.                documentCollection.DocumentActivated += this.DocumentCollection_DocumentActivated;
  262.                this.StateChanged += this.PaletteSet_StateChanged;
  263.            }
  264.        }
  265.  
  266.  
  267.        /// <summary>
  268.        ///     Handles the StateChanged event of the PaletteSet control.
  269.        /// </summary>
  270.        /// <param name="sender">The source of the event.</param>
  271.        /// <param name="e">
  272.        /// The <see cref="Autodesk.AutoCAD.Windows.PaletteSetStateEventArgs" />
  273.        /// instance containing the event data.
  274.        /// </param>
  275.        private void PaletteSet_StateChanged(object sender, PaletteSetStateEventArgs e)
  276.        {
  277.            if (!this._idleHandled && e.NewState == StateEventIndex.Hide)
  278.            {
  279.                this._idleHandled = true;
  280.                this._wasRolledUp = this.RolledUp;
  281.                Application.Idle += this.Application_OnIdle;
  282.            }
  283.            else if (this._idleHandled && e.NewState == StateEventIndex.Show)
  284.            {
  285.                this._idleHandled = false;
  286.                Application.Idle -= this.Application_OnIdle;
  287.            }
  288.        }
  289.  
  290.  
  291.        #endregion Private Methods
  292.    }}

** Edit ** Fixed issue where it would turn palette visible when going from a document that equaled null when the user had manually closed the palette.
** Edit **  Added the Toggle Method
« Last Edit: July 27, 2015, 12:19:26 pm by Keith Brown »
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

MexicanCustard

  • Swamp Rat
  • Posts: 675
Re: Zero Document State and custom tool palettes
« Reply #1 on: February 18, 2014, 08:11:41 am »
Thanks Keith I think I can use that.
Revit 2018, AMEP 2018 64bit Win 10

BlackBox

  • King Gator
  • Posts: 3742
Re: Zero Document State and custom tool palettes
« Reply #2 on: February 18, 2014, 08:29:15 am »
Thanks for sharing, Keith. :beer:
"Potential has a shelf life." - Margaret Atwood

Jeff H

  • Needs a day job
  • Posts: 5853
Re: Zero Document State and custom tool palettes
« Reply #3 on: February 18, 2014, 11:12:56 am »
Thanks Keith!

Keith Brown

  • Swamp Rat
  • Posts: 585
Re: Zero Document State and custom tool palettes
« Reply #4 on: February 18, 2014, 11:25:36 am »
Your welcome all.  This site and its users has helped me out tremendously with the AutoCAD API and i feel that whenever i can give something back that i should.  Nothing groundbreaking about what i posted but it does come in handy.


Now we just need to get more AutoCAD MEP programmers in here!
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Keith Brown

  • Swamp Rat
  • Posts: 585
Re: Zero Document State and custom tool palettes
« Reply #5 on: February 18, 2014, 04:39:24 pm »


I find that I am always writing a command that will toggle the palette on/off.  So in my main code i would write something like this.


Code - C#: [Select]
  1. [CommandMethod("TogglePalette")]
  2. public void TogglePalette()
  3. {
  4.   if (_paletteSet.Visible)
  5.   {
  6.      _paletteSet.Visible = false;
  7.   }
  8.   else
  9.   {
  10.      _paletteSet.Visible = true;
  11.   }
  12. }


I decided to increase the readability and simplify the process.  So in the enhancedpaletteset class i added the following method.


Code - C#: [Select]
  1. public void Toggle()
  2. {
  3.   Visible = !Visible;
  4. }


Now when i need to write a command to toggle the palette set i write code like this.


Code - C#: [Select]
  1. [CommandMethod("TogglePalette")]
  2. public void TogglePalette()
  3. {
  4.   _paletteSet.Toggle();
  5. }




Small changes to the code but i think that it makes a big difference on the amount of code that needs to be written down the line.  Additionally it increases the readability of the code which is always very important to me.

Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Keith Brown

  • Swamp Rat
  • Posts: 585
Re: Zero Document State and custom tool palettes
« Reply #6 on: July 22, 2015, 11:13:42 am »
I updated the code in the original post to check if the active document is equal to null.  Now the paletteset will also close in the new drawing screen introduced in 2015.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Atook

  • Swamp Rat
  • Posts: 841
Re: Zero Document State and custom tool palettes
« Reply #7 on: July 22, 2015, 03:49:16 pm »
Great stuff Keith, I'm just getting into palettes now, so it's perfect timing.

Thank you.

FriendFromArea51

  • Swamp Rat
  • Posts: 675
  • Mars sucks!
Re: Zero Document State and custom tool palettes
« Reply #8 on: July 24, 2015, 01:47:06 am »
this is cool. Thanks! Think i just close mine (don't remember)... was there a reason you didn't want to?.....

Dote! NM... I see you wanted the visible setting to be the same.

mohnston

  • Bull Frog
  • Posts: 304
  • CAD Programmer
Re: Zero Document State and custom tool palettes
« Reply #9 on: July 27, 2015, 10:58:43 am »
I updated the code in the original post to check if the active document is equal to null.  Now the paletteset will also close in the new drawing screen introduced in 2015.
What timing! I just had a palette-based program break because of that new drawingless drawing tab.
Many thanks Keith.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

Keith Brown

  • Swamp Rat
  • Posts: 585
Re: Zero Document State and custom tool palettes
« Reply #10 on: July 27, 2015, 12:23:57 pm »
I am glad it was of use.  Please note that I just updated the code to handle the situation where the user had manually closed the palette and switch to a document state that was null and would then switch back to a valid document.  Previously the code would turn the palette visible again but now it will keep it hidden if it was closed by the user.


To do this I made use of the code posted by Tony Tanzilla located here.  So now the EnhancedPaletteSet also exposes an event that will fire when the palette set is closed by the user or by another software application.  Internally it will not fire when the paletteset closes when switching documents and it encounters a null document.

Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: Zero Document State and custom tool palettes
« Reply #11 on: September 10, 2015, 07:15:22 am »
Hi,

Nice code Keith.

It seems to me that handling the "zero document state" can be done in a simpler way only using the previous visibility state (_wasVisible):

Code - C#: [Select]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using System;
  3.  
  4. namespace Autodesk.AutoCAD.Windows
  5. {
  6.    public class AutoHidePaletteSet : PaletteSet
  7.    {
  8.        bool _wasVisible;
  9.  
  10.        public AutoHidePaletteSet(string name)
  11.            : this(name, name, Guid.NewGuid()) { }
  12.  
  13.        public AutoHidePaletteSet(string name, Guid toolID)
  14.            : this(name, name, toolID) { }
  15.  
  16.        public AutoHidePaletteSet(string name, string cmd, Guid toolID)
  17.            : base(name, cmd, toolID)
  18.        {
  19.            var docs = Application.DocumentManager;
  20.  
  21.            docs.DocumentActivated += (s, e) =>  this.Visible = e.Document == null ? false : _wasVisible;
  22.  
  23.            docs.DocumentCreated += (s, e) => this.Visible = _wasVisible;
  24.  
  25.            docs.DocumentToBeDeactivated += (s, e) => _wasVisible = this.Visible;
  26.  
  27.            docs.DocumentToBeDestroyed += (s, e) => {
  28.                _wasVisible = this.Visible;
  29.                if (docs.Count == 1) this.Visible = false; };
  30.        }
  31.    }
  32. }
« Last Edit: September 11, 2015, 12:23:39 pm by gile »
Speaking English as a French Frog

Keith Brown

  • Swamp Rat
  • Posts: 585
Re: Zero Document State and custom tool palettes
« Reply #12 on: September 11, 2015, 08:30:08 am »
Good stuff as always gile.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: Zero Document State and custom tool palettes
« Reply #13 on: September 11, 2015, 11:22:11 am »
Thanks Keith.

I rewrite the code in a more concise way.
Speaking English as a French Frog