Loading a WPF Window without showing it

前端 未结 12 778
独厮守ぢ
独厮守ぢ 2020-12-12 16:14

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

相关标签:
12条回答
  • 2020-12-12 16:46

    The WindowInteropHelper class should allow you to get the HWND for the WPF window.

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

    MSDN Documentation

    0 讨论(0)
  • 2020-12-12 16:49

    Make the size of the window 0 x 0 px, put ShowInTaskBar to false, show it, then resize it when needed.

    0 讨论(0)
  • 2020-12-12 16:51

    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.

        [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.

    0 讨论(0)
  • 2020-12-12 16:51

    Start Wpf Window in Hidden mode:

    WpfWindow w = new WpfWindow() { Visibility = Visibility.Hidden };
    

    Start Wpf Window in Visible mode:

    WpfWindow w = new WpfWindow();
    w.Show();
    
    0 讨论(0)
  • 2020-12-12 16:56

    I've created extension method for showing invisible window, next Show calls will behave OK.

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-12 16:57

    If you are targeting .NET 4.0 you can make use of the new EnsureHandle method available on the WindowInteropHelper:

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

    (thanks to Thomas Levesque for pointing this out.)

    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:

    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.

    0 讨论(0)
提交回复
热议问题