I haven’t tested this. But this might be a case where you want to, from your RhinoDoc.CloseDocument handler, hookup a RhinoApp.Idle and call Panels.ClosePanel from there.
I tested this using a per document panel and panel constructor with a uint argument representing a document serial number. Please note that the RhinoDoc and RhinoApp event hooks reference static functions. It is important to avoid situations where a static event hook points to a method that may be garbage collected later and then called again when a document closes which will result in Rhino crashing.
Thanks for your example, I just tested code now sorry for late. It did work for document switching but it is not catching for RhinoApp.Closing event. And also when I try to exit rhino without saving anything, it doesn’t catch RhinoAppIdle.
This is my MainPanel which register panel as PerDoc
static EventHandler<DocumentEventArgs> OnCloseDoc;
static EventHandler OnCloseRhino;
// constructor
public MainPanel(uint documentRuntimeSerialNumber)
{
var doc = RhinoDoc.FromRuntimeSerialNumber(documentRuntimeSerialNumber);
ViewModel = doc?.RuntimeData.GetValue(typeof(MyPluginViewModel), rhinoDoc => new MyPluginrViewModel(rhinoDoc.RuntimeSerialNumber));
DataContext = ViewModel;
this.Bind(c => c.Content, ViewModel, m => m.Content);
if (OnCloseDoc == null)
RhinoDoc.CloseDocument += (OnCloseDoc = OnCloseDocument);
if(OnCloseRhino == null)
RhinoApp.Closing += OnCloseRhino = OnRhinoClosing;
}
private void OnRhinoClosing(object sender, EventArgs e)
{
RhinoApp.Idle += RhinoAppIdle;
}
private static void OnCloseDocument(object sender, DocumentEventArgs e)
{
RhinoApp.Idle += RhinoAppIdle;
}
private static void RhinoAppIdle(object sender, EventArgs e)
{
// Wait until there is a new active document
if (RhinoDoc.ActiveDoc != null)
{
// Remove idle hook
RhinoApp.Idle -= RhinoAppIdle;
// Remove doc closed hook;
if (OnCloseDoc != null)
RhinoDoc.CloseDocument -= OnCloseDoc;
if (OnCloseRhino != null)
RhinoApp.Closing -= OnCloseRhino;
OnCloseDoc = null;
Panels.ClosePanel(PanelId);
}
}
public static void RegisterPanel()
{
var icon = DrawingUtilities.IconFromResource("Resources.myPlugin.ico");
if (!registered)
Panels.RegisterPanel(
MyPlugin.Instance,
typeof(MainPanel),
"MyPlugin",
icon,
PanelType.PerDoc);
registered = false;
}
I was wondering is this RhinoApp.Closing didn’t catch RhinoAppIdle event handler because of what you warn me.
Another thing is that why we don’t have Panels.Unregister(panelId) method. Panels.ClosePanel(panelId) actualy just hide panel. It s not so useful I guess. I need to destroy completely.
The panel system is not designed to be used in this way. There is no current way to get exactly what you want. I can make a small change in V7 which will allow you to close the panel without having to use the idle event and will actually work when closing Rhino. You might consider using a modeless form instead of a panel to get what you want. Rhino 7 has an extension method for Eto forms that allows you to associate a form with a document, for example:
[CommandStyle(Style.Hidden)]
public class TestPerDocForm : Rhino.Commands.Command
{
public override string EnglishName => "TestPerDocForm";
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
var form = new Form
{
Content = new RhinoDialogTableLayout(false)
{
Rows =
{
new Button{ Text = LocalName }
}
},
Owner = RhinoEtoApp.MainWindow
};
form.Show(doc);
return Result.Success;
}
}
I went ahead and added a overloaded method Panels.ClosePanel(Guid,RhinoDoc) which you can call directly from the document closing hook passing the document you get in your hook. This will be available in the next 7.3 pre release.