Rhino Switching Focus when WPF window closed

Good Morning,

We are finding unexpected behaviour for Rhino.

Goal:

  • We have a settings WPF Window for our plugin
  • When this closes we want to prompt users whether to save the settings or not
  • To do this we launch another WPF window with Show or with ShowDialogue() to prompt to save

Problem:
This all works however when the user closes the second WPF window we experience strange behaviour - Rhino does not come into focus - instead the last application the user had focused on is brought into view - e.g. Chrome or Explorer or whatever.

To Reproduce:
MyRhinoPlugin1.zip (89.5 KB)

  1. Build and install MyRhinoPlugin1 & run “MyRhinoPlugin1Command”
  2. This will open a WPF window (with its parent set to Rhino)
  3. Close this WPF window
  4. When you close the WPF window another Window will pop up will open asking you to save
  5. Click Yes/No and you will find that Windows shifts the focus back to the last application you had open - and not back to Rhino

We have been careful to follow guidance about Setting the WPF window Owner of both windows to be Rhino but still encounter this issue.

I have produced a sample showing the behaviour and attach it to here.

Problem:
This all works however when the user closes the second WPF window we experience strange behaviour - Rhino does not come into focus - instead the last application the user had focused on is brought into view - e.g. Chrome or Explorer or whatever.

I’ve tested your plugin, but its behavior is ok! it gets back to rhino

I have tested the example plugin. The first time I tried I did not encounter the error however, subsequent test the error occurred. I have attached a screen capture showing the behavior.

1 Like

I had tried 4 or 5 times, 2 times restarted rhino, but didnt encounter this problem

Instead of the weird new WindowInteropHelper incantation you should use do the following:

            TEstWindow window = new TEstWindow();
            window.Owner = Rhino.UI.RhinoEtoApp.MainWindow.ControlObject as System.Windows.Window;
            window.Show();

and in the OnClosing handler of TEstWindow

          Window window = new Window {
              Title = "Save your Settings?"
          };
          window.Owner = Rhino.UI.RhinoEtoApp.MainWindow.ControlObject as System.Windows.Window;
          window.Show();
1 Like

Thank you @nathanletwory That does indeed solve the problem :slight_smile:

The weird Incantation (good word!) was recommended in several threads on here & did solve a problem where parenting doesn’t work correctly - your solution also solves that & doesn’t have this bug :slight_smile:

I see. If you ever need to create an instance of WindowInteropHelper, or any class for that matter, you should use a clear style:

WindowInteropHelper wih = new WindowInteropHelper(window);
wih.Owner = someOwnerValidObject;

Refrain from cramming those on one line, since it is hard to read, and it is easy to miss you are actually instantiating an object that you intend to use.

Glad to hear your problem is now solved. Have fun developing your plug-in!

Hi @nathanletwory,

We’ve had a further bug report. When user switches focus away from Rhino with WPF window open they are sometimes unable to bring the WPF window back into view.

You can see the behaviour in the attached gif.
This uses the attached demo plugin - which includes your suggested fix.
Looking at this fix in the debugger I am a little perplexed as Owner is always set to null?
ControlObject is of type IntPtr and there is no possible type conversion to Window.

Rhino.UI.RhinoEtoApp.MainWindow.ControlObject.GetType().Name
"IntPtr"

test
MyRhinoPlugin1.zip (46.3 KB)

I’ll have to defer to @curtisw , I am not familiar enough with the WPF system and conversion of Eto controls to their native counter-parts.

Hey @david.birch.uk,

As you pointed out, RhinoEtoApp.MainWindow.ControlObject is indeed an IntPtr, and the code you had to set the owner before was correct and is also what Eto does when setting the owner of WPF windows to the main window.

The reason you’re seeing the behaviour is because you are showing a new modeless window while the other is closing but not actually closed yet. The main window at that point is not actually active so when the new one closes it does not restore it to active state (because it wasn’t active when it was initially shown).

You have two options really:

  1. Use ShowDialog() for the second window, and set its owner to your first window. This makes the most sense to me given that the second window is meant to ask if you want to save. If you want a “cancel” option this would allow you to cancel closing the first window using the event arguments in the OnClosing method.

  2. Use the Closed event (vs. Closing) to show the second window after the first closes, not before it closes.

2 Likes

Thank you @curtisw. That makes good sense.

I have implemented option 2 with ShowDialog and can confirm that it resolves both bugs :slight_smile:

Much appreciated

2 Likes