加载一个WPF窗口而不显示它

我创build一个全局热键,通过PInvoking RegisterHotKey()显示一个窗口。 但是为了做到这一点,我需要那个窗口的HWND ,它在窗口加载之前不存在,这意味着第一次显示。 但我不想在设置热键之前显示窗口。 有没有办法为该窗口创build一个用户不可见的HWND

如果您的目标是.NET 4.0,则可以使用EnsureHandle提供的新的EnsureHandle方法:

 public void InitHwnd() { var helper = new WindowInteropHelper(this); helper.EnsureHandle(); } 

(感谢Thomas Levesque 指出了这一点。 )

如果您的目标是早期版本的.NET Framework,最简单的方法是显示窗口以访问HWND,同时设置一些属性以确保窗口不可见并且不会窃取焦点:

 var window = new Window() //make sure the window is invisible { Width = 0, Height = 0, WindowStyle = WindowStyle.None, ShowInTaskbar = false, ShowActivated = false }; window.Show(); 

一旦你想显示实际的窗口,你可以设置内容,大小和风格改回到一个正常的窗口。

这是一个肮脏的黑客,但它应该工作,并没有改变不透明度的缺点:

  • WindowStartupLocation设置为Manual
  • TopLeft属性设置为屏幕外的某个位置
  • ShowInTaskbar设置为false,以便用户不知道有一个新的窗口
  • ShowHide窗口

您现在应该能够检索HWND

编辑:另一个选项,可能更好:设置ShowInTaskBar为false和WindowState Minimized ,然后显示它:它将不会显示在所有

您也可以将窗口更改为所谓的仅消息窗口。 由于此窗口types不支持graphics元素,因此将不会显示。 基本上可以归结为呼吁:

  SetParent(hwnd, (IntPtr)HWND_MESSAGE); 

创build一个始终隐藏的专用消息窗口,或者使用真实的GUI窗口,并在需要显示时将其更改回普通窗口。 有关更完整的示例,请参阅下面的代码。

  [DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hwnd, IntPtr hwndNewParent); private const int HWND_MESSAGE = -3; private IntPtr hwnd; private IntPtr oldParent; protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; if (hwndSource != null) { hwnd = hwndSource.Handle; oldParent = SetParent(hwnd, (IntPtr)HWND_MESSAGE); Visibility = Visibility.Hidden; } } private void OpenWindowMenuItem_Click(object sender, RoutedEventArgs e) { SetParent(hwnd, oldParent); Show(); Activate(); } 

对我来说,将宽度,高度设置为零以及样式设置为none的解决scheme都不能解决,因为它仍然显示了一个小窗口,带有一个令人讨厌的阴影,似乎是围绕0x0窗口的边界(在Windows 7上进行了testing)。 因此,我正在提供这个替代选项。

我已经发布了这个问题的答案,但我只是find了一个更好的解决scheme。

如果您只需要确认HWND是否已创build,而不实际显示窗口,则可以这样做:

  public void InitHwnd() { var helper = new WindowInteropHelper(this); helper.EnsureHandle(); } 

(实际上,当问题发布时, EnsureHandle方法不可用,它在.NET 4.0中引入)

我从来没有试过做你正在做的事情,但是如果你需要显示窗口来获取HWND,但不想显示它,那么将Window Opacity设置为0.这也将防止发生任何命中testing。 然后,您可以在窗口上使用公共方法将不透明度更改为100,以使其可见。

我对WPF一无所知,但是可以使用其他方法(例如PInvoke)创build一个仅用于消息窗口来接收WM_HOTKEY消息吗? 如果是的话,那么一旦你收到WM_HOTKEY,你可以从那里启动WPF窗口。

WindowInteropHelper类应该允许您获取WPF窗口的HWND。

 MyWindow win = new MyWindow(); WindowInteropHelper helper = new WindowInteropHelper(win); IntPtr hwnd = helper.Handle; 

MSDN文档

以类似的方式将不透明度设置为0的另一个选项是将大小设置为0并将位置设置为离开屏幕。 这将不需要AllowsTransparency = True。

另外请记住,一旦你显示一次,你可以隐藏它,仍然得到的HWND。

使窗口的大小为0 x 0 px,将ShowInTaskBar设置为false,显示它,然后在需要时resize。

我已经创build了用于显示不可见窗口的扩展方法,接下来Show调用将performance正常。

 public static class WindowHelper { public static void ShowInvisible(this Window window) { // saving original settings bool needToShowInTaskbar = window.ShowInTaskbar; WindowState initialWindowState = window.WindowState; // making window invisible window.ShowInTaskbar = false; window.WindowState = WindowState.Minimized; // showing and hiding window window.Show(); window.Hide(); // restoring original settings window.ShowInTaskbar = needToShowInTaskbar; window.WindowState = initialWindowState; } }