In the last post, we saw some code that provided a relatively crude mechanism for finding out when a particular custom palette set gets closed by the user.
In this post, we encapsulate this technique in a new class – which I’ve called PaletteSet2, for the want of a better name – that can be used to apply it to a number of custom palette sets at once.
Here’s the C# code for the new PaletteSet2 implementation:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using System;
[assembly: CommandClass(typeof(PaletteSet2))]
namespace Autodesk.AutoCAD.Windows
{
public class PaletteSet2 : PaletteSet
{
// Hold a static pointer to the palette set being closed
public static PaletteSet2 Current = null;
// Our static event to be fired on close
public static event EventHandler PaletteSetClosed;
// In the constructor we add an event handler to check
// for changes of state (show/hide)
public PaletteSet2(string name) : base(name)
{
this.StateChanged +=
(s, e) =>
{
// On hide we fire a command to check the state properly
if (e.NewState == StateEventIndex.Hide)
{
// Set the static property to point to our palette
PaletteSet2.Current = this;
// Launch the command quietly
Application.DocumentManager.MdiActiveDocument.
SendStringToExecute(
"CHECKPALETTESETCLOSE ", true, true, false
);
}
};
}
// For some reason we need a default constructor with 0 args
public PaletteSet2()
: base("")
{
}
// Our command implementation
[CommandMethod("CHECKPALETTESETCLOSE", CommandFlags.NoHistory)]
public static void CheckPaletteSetState()
{
// Get the static instance set
PaletteSet2 ps = Current;
// If it's invisible, it has been closed
if (ps != null && !ps.Visible)
{
// Set the static instance to null and fire the
// subscribed event
Current = null;
if (PaletteSetClosed != null)
{
PaletteSetClosed(ps, new EventArgs());
}
}
}
}
}
Here’s some code that can be used to test it, creating two distinct palette sets that will have their close event monitored.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
[assembly: CommandClass(typeof(Test.Commands))]
namespace Test
{
public class Commands
{
private static PaletteSet2 _ps1 = null, _ps2 = null;
[CommandMethod("PSTEST")]
public static void CreatePaletteSet()
{
bool attachEvent = false;
if (_ps1 == null)
{
_ps1 = new PaletteSet2("First PaletteSet to Close");
_ps1.Style =
PaletteSetStyles.NameEditable |
PaletteSetStyles.ShowPropertiesMenu |
PaletteSetStyles.ShowAutoHideButton |
PaletteSetStyles.ShowCloseButton;
_ps1.MinimumSize = new System.Drawing.Size(300, 300);
attachEvent = true;
}
if (_ps2 == null)
{
_ps2 = new PaletteSet2("Second PaletteSet to Close");
_ps2.Style =
PaletteSetStyles.NameEditable |
PaletteSetStyles.ShowPropertiesMenu |
PaletteSetStyles.ShowAutoHideButton |
PaletteSetStyles.ShowCloseButton;
_ps2.MinimumSize = new System.Drawing.Size(300, 300);
attachEvent = true;
}
// Only attach the static event if we just created
// a palette set
if (attachEvent)
{
// We subscribe to a static event, which is a bit
// anomalous (but hey)
PaletteSet2.PaletteSetClosed +=
(s, e) =>
{
PaletteSet2 ps = s as PaletteSet2;
if (ps != null)
{
Application.DocumentManager.MdiActiveDocument.
Editor.WriteMessage(
"\n\"{0}\" closed!", ps.Name
);
}
};
}
_ps1.Visible = true;
_ps2.Visible = true;
}
}
}
This version of the PSTEST creates two palette sets, which are initially docked. Something I should have mentioned about the reason for implementing a command, in the first place: the standard StateChanged event gets fired twice when undocking a palette set – once to hide it and once to display it again. This means we can’t assume a hide notification means the palette set is being closed – we really need to wait until the dust has settled before checking the state of the palette set in order to proclaim our verdict. Which is why we’re sending a command to be executed (and in fact may send it a few times – as we could well be receiving multiple hide notifications if undocking the palette set – which is just fine, as it’s only the first command invocation that does anything interesting).
Here are those palette sets undocked:
When we close these palette sets, we see at the command-line that each has been correctly identified in our event handler:
Command:
"First PaletteSet to Close" closed!
Command:
"Second PaletteSet to Close" closed!
There is one thing, in particular, that I find less than ideal about this implementation: we’re implementing/firing a static event from the PaletteSet2 class, which means we only set the handler once for the class, but it also means we don’t get custom close behaviour for each palette set. We could check the name of the palette set when closing to implement custom behaviour, should we so desire, but it’s not quite as simple as having a custom event defined for each instance.
If anyone can find a way to implement this approach using a non-static event – or has some other improvement to suggest regarding the above technique – please do post a comment.
That’s it for now, in this last post before Christmas (and probably of 2011, although I may yet queue something up for next week, if I have the time). May all the readers of this blog have a wonderful festive season – I’ll be back with more posts in 2012. A Merry Christmas and a Happy New Year, to those of you who celebrate them! :-)