The UserControl you register as a Panel is nested inside of a windows, which is nested inside of a tabbed window, which is nested inside of a docking frame window.
When you click the “X” to close the docking frame, you are only effecting the docking frame itself, which is why your UserControl’s VisibleChanged event is not triggered.
A docking dialog, created in C++, receives these types of events because the class you must inherit from provides virtual functions for these events. The RhinoCommon implementation is much simpler - all you have to do is create a UserControl and register it as a panel.
One solution would be for us to provide some events on Rhino.UI.Panels that you could subscribe to if you wanted to be notified if your tab was shown or hidden, or if the owning dockbar was shown or hidden. I’ve add a request for such events to the RhinoCommon wish list.