Ohhhh ... okay, figured this out. Hopefully this will continue to work and be useful for others, and event handlers don't get updated somewhere unexpectedly, but it would be good to confirm.
It isn't sufficient to implement a _VisibleChanged(object sender, EventArgs e) event handler within the CTP form itself, as it won't get called when it is closed using the 'X' or the Close option from the CTP dropdown.
From examples here in the group, I implemented a CTPManager class, only using a dictionary that houses all the created CTPs rather than a single object, then on the ShowCTP() method takes an enum for the Custom Task Pane I want, created a new one if it's not already in the dictionary, make all existing CTPs invisible, then make the CTP to show visible.
private static readonly Dictionary<TaskPaneForm, CustomTaskPane> ctps = new();
public static void ShowCTP(TaskPaneForm taskPaneForm)
{
if (!ctps.ContainsKey(taskPaneForm))
{
CTP ctp = ctpm[taskPaneForm];
ctps.Add(taskPaneForm, CustomTaskPaneFactory.CreateCustomTaskPane(ctp.Type, ctp.Header));
ctps[taskPaneForm].Width = 400;
}
Now in the ITaskPaneForm interface class, I added this method to be implemented by every Custom Task Pane form:
public void VisibleStateChanged(CustomTaskPane CustomTaskPaneInst);
And on creation of a new CTP form using the CustomTaskPaneFactory.CreateCustomTaskPane() method, I follow it with:
ITaskPaneForm ctpf = (ITaskPaneForm)ctps[taskPaneForm].ContentControl;
ctps[taskPaneForm].VisibleStateChange += ctpf.VisibleStateChanged;
Then each Customer Task Pane form method implementing this can have it's own visible changed event handler. Unlikely the normal CTP form _VisibleChanged() event, his method *does* get called when the 'X' is clicked, and I now have a way to know when I need to reset form data, cancel the current operation, and cleanup any objects in memory I no longer need there.
Thanks,
Mickey