如何在不同的线程中将窗口保持在另一个窗口的顶部?

时间:2009-05-08 14:06:16

标签: wpf windows winforms

我有一个WinForms表单(称之为'MyForm'),它承载一些WPF UI(通过ElementHost)。我在主UI线程的单独线程上显示此表单。

我希望'MyForm'保持在主应用程序窗口的顶部,所以我使用Show方法的Show(IWin32Window)重载来显示表单,传入的IWin32Window是主应用程序窗口。

窗口通过'启动器窗体'间接显示,启动器窗体是单独的STA线程(传递给Application.Run的线程)的“应用程序窗体”。原因是您在通过Application.Run启动表单时无法指定所有者窗口。

以下是启动MyForm的代码(用作STA线程的ThreadStart):

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.
}

'发射器'形式:

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);
  }
}

这几乎可行。 'MyForm'停留在主应用程序窗口的顶部,但只有在我用工具提示鼠标悬停在WPF控件上之后。显示工具提示时,“MyForm”将消失在主应用程序窗口后面。当我在我的表单上鼠标悬停WinForms控件以显示其工具提示时,这不会发生 - 它似乎特定于WPF控件。

只有当MyForm是前景窗口时才会发生。

请注意,当我使用MyForm作为应用程序表单(跳过启动器)并覆盖MyForm的OnLoad方法以使用SetWindowLong设置其所有者时,我会遇到同样的问题。这是一种较少参与的方式,但我想使用一种不使用P-Invoke的机制来查看这是否会更好。两种方法都以同样的方式被打破。

更新 测试应用程序意味着此问题特定于在Visual Studio向导扩展中显示UI。我认为这使得它更加利基,甚至不太可能得到回答!

1 个答案:

答案 0 :(得分:0)

以下MSDN文章是关于WinAPI调用的,但它希望能让您对不同线程之间的窗口激活有所了解(我假设您必须直接将P / Invoke引入WinAPI,除非您可以避免在多个线程上使用您的UI ):

  

Multiple Threads in the User Interface

(特别参见窗口焦点和激活注意事项部分)