加载 WPF 窗口而不显示它
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1399037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loading a WPF Window without showing it
提问by svick
I create a global hot key to show a window by PInvoking RegisterHotKey()
. But to do this I need that window's HWND
, which doesn't exist until the window is loaded, that means shown for the first time. But I don't want to show the window before I can set the hot key. Is there a way to create a HWND
for that window that is invisible to the user?
我创建了一个全局热键来通过 PInvoking 显示一个窗口RegisterHotKey()
。但是要做到这一点,我需要那个窗口的HWND
,它在窗口加载之前不存在,这意味着第一次显示。但是我不想在设置热键之前显示窗口。有没有办法HWND
为该窗口创建一个对用户不可见的窗口?
回答by Patrick Klug
If you are targeting .NET 4.0 you can make use of the new EnsureHandle
method available on the WindowInteropHelper
:
如果您的目标是 .NET 4.0,您可以使用以下EnsureHandle
网站上提供的新方法WindowInteropHelper
:
public void InitHwnd()
{
var helper = new WindowInteropHelper(this);
helper.EnsureHandle();
}
(thanks to Thomas Levesque for pointing this out.)
(感谢 Thomas Levesque指出这一点。)
If you are targeting an older version of the .NET Framework, the easiest way is to show the window to get to the HWND while setting a few properties to make sure that the window is invisible and doesn't steal focus:
如果您的目标是旧版本的 .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();
Once you want to show the actual window you can then set the Content, the size and change the style back to a normal window.
一旦您想显示实际窗口,您就可以设置内容、大小并将样式更改回普通窗口。
回答by DJP
You can also change the window into a so called message-only window. As this window type does not support graphical elements it will never be shown. Basically it comes down to calling:
您还可以将窗口更改为所谓的仅消息窗口。由于此窗口类型不支持图形元素,因此永远不会显示。基本上它归结为调用:
SetParent(hwnd, (IntPtr)HWND_MESSAGE);
Either create a dedicated message window which will always be hidden, or use the real GUI window and change it back to a normal window when you want to display it. See the code below for a more complete example.
要么创建一个始终隐藏的专用消息窗口,要么使用真实的 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();
}
For me the solution of setting the width, height to zero and style to none didn't work out, as it still showed a tiny window, with an annoying shadow of what seems to be the border around a 0x0 window (tested on Windows 7). Therefore I'm providing this alternative option.
对我来说,将宽度、高度设置为零和样式设置为无的解决方案没有奏效,因为它仍然显示一个小窗口,带有一个令人讨厌的阴影,似乎是 0x0 窗口周围的边框(在 Windows 7 上测试) )。因此我提供了这个替代选项。
回答by Thomas Levesque
This is a dirty hack, but it should work, and doesn't have the downsides of changing the opacity :
这是一个肮脏的黑客,但它应该可以工作,并且没有更改不透明度的缺点:
- set the
WindowStartupLocation
toManual
- set the
Top
andLeft
properties to somewhere outside the screen - set
ShowInTaskbar
to false so that the user doesn't realize there is a new window Show
andHide
the window
- 设置
WindowStartupLocation
为Manual
- 将
Top
和Left
属性设置为屏幕外的某个位置 - 设置
ShowInTaskbar
为 false 以便用户不会意识到有一个新窗口 Show
和Hide
窗户
You should now be able to retrieve the HWND
您现在应该能够检索 HWND
EDIT: another option, probably better : set ShowInTaskBar
to false and WindowState
to Minimized
, then show it : it won't be visible at all
编辑:另一个选项,可能更好:设置ShowInTaskBar
为 false 和WindowState
to Minimized
,然后显示它:它根本不可见
回答by Thomas Levesque
I had already posted an answer to that question, but I just found a better solution.
我已经发布了该问题的答案,但我刚刚找到了更好的解决方案。
If you just need to make sure that the HWND is created, without actually showing the window, you can do this:
如果您只需要确保创建了 HWND,而不实际显示窗口,您可以这样做:
public void InitHwnd()
{
var helper = new WindowInteropHelper(this);
helper.EnsureHandle();
}
(actually the EnsureHandle
method wasn't available when the question was posted, it was introduced in .NET 4.0)
(实际上EnsureHandle
问题发布时该方法不可用,它是在.NET 4.0中引入的)
回答by Joel Cochran
I've never tried to do what you are doing, but if you need to show the Window to get the HWND, but don't want to showit, set the Window Opacity to 0. This will also prevent any hit testing from occurring. Then you could have a public method on the Window to change the Opacity to 100 when you want to make it visible.
我从来没有尝试做你正在做的事情,但是如果你需要显示窗口来获取 HWND,但不想显示它,请将窗口不透明度设置为 0。这也将防止发生任何命中测试. 然后你可以在 Window 上有一个公共方法,当你想让它可见时将不透明度更改为 100。
回答by Agnel Kurian
I know absolutely nothing about WPF, but could you create a message only windowusing other means (PInvoke for example) to receive the WM_HOTKEY message? If yes, then once you receive the WM_HOTKEY, you could launch the WPF window from there.
我对 WPF 一无所知,但是您能否使用其他方式(例如 PInvoke)创建一个仅消息窗口来接收 WM_HOTKEY 消息?如果是,那么一旦您收到 WM_HOTKEY,您就可以从那里启动 WPF 窗口。
回答by Chandraprakash
Start Wpf Window in Hidden mode:
以隐藏模式启动 Wpf 窗口:
WpfWindow w = new WpfWindow() { Visibility = Visibility.Hidden };
//w.Show();
Start Wpf Window in Visible mode:
在可见模式下启动 Wpf 窗口:
WpfWindow w = new WpfWindow();
w.Show();
回答by Vadim Ovchinnikov
I've created extension method for showing invisible window, next Show
calls will behave OK.
我已经创建了用于显示不可见窗口的扩展方法,接下来的Show
调用将正常运行。
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;
}
}
回答by Nullcaller
I've noticed that the last thing that happens when the window is being initialized, is the change of WindowState
, if it differs from normal. So, you can actually make use of it:
我注意到初始化窗口时发生的最后一件事是 的变化WindowState
,如果它与正常不同。所以,你实际上可以使用它:
public void InitializeWindow(Window window) {
window.Top = Int32.MinValue;
window.Left = Int32.MinValue;
window.Width = 0;
window.Height = 0;
window.ShowActivated = false;
window.ShowInTaskbar = false;
window.Opacity = 0;
window.StateChanged += OnBackgroundStateChanged;
window.WindowStyle = WindowStyle.None;
}
public void ShowWindow(Window window) {
window.Show();
window.WindowState = WindowState.Maximized;
}
protected bool isStateChangeFirst = true;
protected void OnBackgroundStateChanged(object sender, EventArgs e) {
if (isStateChangeFirst) {
isStateChangeFirst = false;
window.Top = 300;
window.Left = 200;
window.Width = 760;
window.Height = 400;
window.WindowState = WindowState.Normal;
window.ShowInTaskbar = true;
window.Opacity = 1;
window.Activate();
}
}
That works fair enough for me. And it does not require working with any handles and stuff, and, more importantly, does not require to have a custom class for a window. Which is great for dynamically loaded XAML. And it is also a great way if you are making a fullscreen app. You do not even need to change its state back to normal or set proper width and height. Just go with
这对我来说足够公平。它不需要使用任何句柄和东西,更重要的是,不需要为窗口提供自定义类。这对于动态加载的 XAML 非常有用。如果您正在制作全屏应用程序,这也是一个很好的方法。您甚至不需要将其状态更改回正常或设置适当的宽度和高度。随走
protected bool isStateChangeFirst = true;
protected void OnBackgroundStateChanged(object sender, EventArgs e) {
if (isStateChangeFirst) {
isStateChangeFirst = false;
window.ShowInTaskbar = true;
window.Opacity = 1;
window.Activate();
}
}
And you're done.
你已经完成了。
And even if I am wrong in my assumption that change of state is last thing done when window is being loaded, you can still change to any other event, it does not really matter.
即使我假设状态更改是加载窗口时最后完成的事情是错误的,您仍然可以更改为任何其他事件,这并不重要。
回答by luvieere
Make the size of the window 0 x 0 px, put ShowInTaskBar to false, show it, then resize it when needed.
使窗口的大小为 0 x 0 px,将 ShowInTaskBar 设置为 false,显示它,然后在需要时调整它的大小。