views:

487

answers:

1

I have a WinForms form (call it 'MyForm') that hosts some WPF UI (via ElementHost). I show this form on a separate thread from the main UI thread.

I want 'MyForm' to remain on top of the main application window, so I am showing the form using the Show(IWin32Window) overload of the Show method, with the passed-in IWin32Window being the main app window.

The window is shown indirectly via a 'launcher form' which is the 'application form' of the separate STA thread (the one passed in to Application.Run). The reason for this is that you can't specify an owner window when launching a form via Application.Run.

Here is the code to launch MyForm (used as the ThreadStart for an STA thread):

void MyWindowThread()
{
  myForm = new MyForm();
  var launcherForm = new LauncherForm(myForm, mainWindow);
  Application.Run(new ApplicationContext(launcherForm));
  // launcherForm will Show myForm when it itself is shown.
}

The 'launcher' form:

public partial class LauncherForm : Form
{
  private readonly MyForm _myForm;
  private readonly IWin32Window _mainWindow;

  public WizardUILauncherForm(MyForm myForm, IWin32Window mainWindow)
  {
    _myForm = myForm;
    _mainWindow = mainWindow;
    InitializeComponent();
  }

  protected override void OnShown(EventArgs e)
  {
    // show the actual form that the user will interact with, on top of mainWindow.
    _myForm.Show(_mainWindow);
  }
}

This almost works. 'MyForm' stays on top of the main app window, but only until I mouse over a WPF control with a tooltip. When the tooltip is shown, 'MyForm' disappears behind the main application window. This doesn't happen when I mouseover a WinForms control on my form to display its tooltip - it seems specific to WPF controls.

It also only happens when MyForm is the foreground window.

Note that I get the same problem when I use MyForm as the application form (skipping out the launcher) and override MyForm's OnLoad method to set its owner using SetWindowLong. This is a less involved way of doing it, but I wanted to use a mechanism that didn't use P-Invoke, to see if this would work better. Both methods are broken in the same way.

Update A test application implies that this problem is specific to showing UI in a Visual Studio wizard extension. Which I suppose makes it even more niche and even less likely to be answered!

A: 

The following MSDN article is about WinAPI calls but it will hopefully give you some insight on window activation between different threads (I assume you will have to P/Invoke into the WinAPI directly anyway unless you can avoid having your UI on multiple threads):

Multiple Threads in the User Interface

(especially see the section on Window Focus and Activation Considerations)

0xA3