加载一个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
- 将
Top
和Left
属性设置为屏幕外的某个位置 - 将
ShowInTaskbar
设置为false,以便用户不知道有一个新的窗口 -
Show
和Hide
窗口
您现在应该能够检索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; } }