加载WPF窗口而不显示它

svi*_*ick 50 wpf window hwnd

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

Pat*_*lug 64

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

public void InitHwnd()
{
    var helper = new WindowInteropHelper(this);
    helper.EnsureHandle();
}
Run Code Online (Sandbox Code Playgroud)

(感谢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();
Run Code Online (Sandbox Code Playgroud)

一旦您想要显示实际窗口,您就可以设置内容,大小并将样式更改回正常窗口.

  • 是的,这很有效,谢谢.甚至不需要设置WindowState.另外,我在XAML中设置Window的内容,但这并不重要.另一件事是WindowStartupLocation = CenterScreen不能以这种方式正常工作,但这很容易修复. (2认同)

DJP*_*DJP 17

您还可以将窗口更改为所谓的仅消息窗口.由于此窗口类型不支持图形元素,因此永远不会显示.基本上它归结为:

    SetParent(hwnd, (IntPtr)HWND_MESSAGE);
Run Code Online (Sandbox Code Playgroud)

创建一个始终隐藏的专用消息窗口,或者使用真实的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();
    }
Run Code Online (Sandbox Code Playgroud)

对我来说,将宽度,高度设置为零并将样式设置为无的解决方案无法解决,因为它仍然显示一个小窗口,带有恼人的阴影,似乎是围绕0x0窗口的边框(在Windows 7上测试) ).因此我提供这种替代选择.


Tho*_*que 16

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

  • 设置WindowStartupLocationManual
  • TopLeft属性设置为屏幕外的某个位置
  • 设置ShowInTaskbar为false,以便用户没有意识到有一个新窗口
  • ShowHide窗口

您现在应该能够检索HWND

编辑:另一种选择,可能更好:设置ShowInTaskBar为false和WindowStateto Minimized,然后显示它:它根本不可见

  • +1 ShowInTaskBar = false和WindowState = Minimized工作. (2认同)
  • 使用您的另一个选项,我可以在屏幕的左下角看到窗口最小化.但第一个看起来很有希望. (2认同)

Tho*_*que 11

我已经发布了这个问题的答案,但我刚刚找到了一个更好的解决方案.

如果您只需要确保创建HWND,而不实际显示窗口,则可以执行以下操作:

    public void InitHwnd()
    {
        var helper = new WindowInteropHelper(this);
        helper.EnsureHandle();
    }
Run Code Online (Sandbox Code Playgroud)

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


Joe*_*ran 5

我从未试图做你正在做的事情,但是如果你需要显示Window来获得HWND,但又不想显示它,请将Window Opacity设置为0.这也将阻止任何命中测试的发生.然后,您可以在窗口上使用公共方法将"不透明度"更改为100,以使其可见.