Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
加载WPF窗口而不显示它_Wpf_Window_Hwnd - Fatal编程技术网

加载WPF窗口而不显示它

加载WPF窗口而不显示它,wpf,window,hwnd,Wpf,Window,Hwnd,我通过PInvokingRegisterHotKey()创建一个全局热键来显示窗口。但要做到这一点,我需要窗口的HWND,它在加载窗口之前不存在,这意味着第一次显示。但我不想在设置热键之前显示窗口。是否有方法为用户不可见的窗口创建HWND?WindowInteropHelper类应允许您获取WPF窗口的HWND MyWindow win = new MyWindow(); WindowInteropHelper helper = new WindowInteropHelper(win); In

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

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

MyWindow win = new MyWindow();
WindowInteropHelper helper = new WindowInteropHelper(win);

IntPtr hwnd = helper.Handle;

我从未尝试过执行您正在执行的操作,但是如果您需要显示窗口以获取HWND,但不想显示,请将窗口不透明度设置为0。这也将防止发生任何命中测试。然后你可以在窗口上有一个公共方法,当你想要使不透明度可见时,将其更改为100。

另一个类似于将不透明度设置为0的方法是将大小设置为0,并将位置设置为远离屏幕。这不需要AllowsTransparency=True


还要记住,一旦你展示了它,你就可以隐藏它,仍然可以得到hwnd。

这是一个肮脏的破解,但它应该可以工作,并且没有改变不透明度的缺点:

  • WindowStartupLocation
    设置为
    Manual
  • 顶部
    左侧
    属性设置为屏幕外的某个位置
  • ShowInTaskbar
    设置为false,这样用户就不会意识到有一个新窗口
  • 显示
    隐藏
    窗口
您现在应该能够检索HWND了


编辑:另一个选项,可能更好:将
ShowInTaskBar
设置为false,将
WindowState
设置为
Minimized
,然后显示它:如果您的目标是.NET 4.0,它将根本不可见。您可以使用
WindowInteropHelper
上提供的新的
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();

一旦你想显示实际窗口,你就可以设置内容、大小并将样式改回普通窗口。

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

我对WPF一无所知,但你能用其他方法(例如PInvoke)创建一个新窗口吗要接收WM_热键消息?如果是,那么一旦您收到WM_热键,您就可以从那里启动WPF窗口。

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

    SetParent(hwnd, (IntPtr)HWND_MESSAGE);
创建一个始终隐藏的专用消息窗口,或者使用真正的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();
    }

对我来说,将宽度、高度设置为零,将样式设置为无的解决方案不起作用,因为它仍然显示一个小窗口,在0x0窗口周围有一个恼人的阴影(在Windows7上测试)。因此,我提供了这个备选方案。

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

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

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

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

我已经创建了用于显示不可见窗口的扩展方法,接下来的
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;
    }
}

我注意到,初始化窗口时发生的最后一件事是更改
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();
    }
}
这对我来说很公平。它不需要使用任何句柄和其他东西,更重要的是,不需要为窗口创建自定义类。这对于动态加载的XAML非常有用。如果你正在制作一个全屏应用程序,这也是一个很好的方法。您甚至不需要将其状态更改回正常状态或设置适当的宽度和高度。随你的便

protected bool isStateChangeFirst = true;
protected void OnBackgroundStateChanged(object sender, EventArgs e) {
    if (isStateChangeFirst) {
        isStateChangeFirst = false;

        window.ShowInTaskbar = true;
        window.Opacity = 1;
        window.Activate();
    }
}
你完成了

即使我的假设是错误的,即在加载窗口时状态的改变是最后一件事,您仍然可以更改为任何其他事件,这并不重要

在隐藏模式下启动Wpf窗口:

在可见模式下启动Wpf窗口:


这就是我正在做的,但是这样,窗口还没有HWND,所以helper.Handle是0,这不是我需要的。很奇怪,要使不透明度设置有效,AllowTransparency必须设置为true,这反过来会将WindowsStyle强制为WindowsStyle。无,这不是我想要的。此外,AllowTransparency在显示窗口后无法更改,因此我无法在显示后将其设置回原位。使用另一个选项,我可以在屏幕左下角看到最小化的窗口。但是第一个看起来很有希望。@svick:你用的是哪个操作系统?在Windows7上最小化的窗口不可见啊,是的,我记得这个行为。。。在Win7(或者Vista)中它似乎已经改变了。是的,这很有效,谢谢。甚至不需要设置WindowsState。另外,我用XAML设置了窗口的内容,但这并不重要。另一件事是WindowsStartupLocation=CenterScreen无法以这种方式正常工作,但这很容易修复。已删除WindowsState设置程序。。。感谢您让我知道。我也要添加
ResizeMode=ResizeMode.NoResize
,因为它会删除窗口边框以调整大小。如果您有此设置,请不要忘记设置最小宽度/高度。可能还需要添加“可见性=可见性.隐藏”(取自
WpfWindow w = new WpfWindow() { Visibility = Visibility.Hidden };
WpfWindow w = new WpfWindow();
w.Show();