Подтвердить что ты не робот

Загрузка окна WPF без его отображения

Я создаю глобальную горячую клавишу, чтобы показать окно с помощью PInvoking RegisterHotKey(). Но для этого мне нужно это окно HWND, которое не существует до тех пор, пока окно не будет загружено, это означает, что показано в первый раз. Но я не хочу показывать окно, прежде чем я могу установить горячую клавишу. Есть ли способ создать HWND для этого окна, которое невидимо для пользователя?

4b9b3361

Ответ 1

Если вы настроили таргетинг на .NET 4.0, вы можете использовать новый метод EnsureHandle, доступный в WindowInteropHelper:

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

(спасибо Томасу Левеску за указав это.)

Если вы ориентируетесь на более раннюю версию .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();

Как только вы захотите отобразить фактическое окно, вы можете установить контент, размер и изменить стиль обратно в обычное окно.

Ответ 2

Это грязный хак, но он должен работать и не имеет недостатков в изменении непрозрачности:

  • установите WindowStartupLocation в Manual
  • установите свойства Top и Left где-то вне экрана
  • установите ShowInTaskbar в false, чтобы пользователь не понимал, что есть новое окно
  • Show и Hide окно

Теперь вы можете получить HWND

EDIT: еще один вариант, возможно, лучше: установите ShowInTaskbar на false и WindowState на Minimized, а затем покажите его: он вообще не будет отображаться

Ответ 3

Вы также можете изменить окно в так называемое окно только для сообщений. Поскольку этот тип окна не поддерживает графические элементы, он никогда не будет показан. В основном это сводится к вызову:

    SetParent(hwnd, (IntPtr)HWND_MESSAGE);

Либо создайте выделенное окно сообщений, которое всегда будет скрыто, либо используйте реальное окно графического интерфейса пользователя и верните его в обычное окно, когда вы хотите его отобразить. См. Приведенный ниже код для более полного примера.

    [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 (проверено на Windows 7). Поэтому я предоставляю этот альтернативный вариант.

Ответ 4

Я уже опубликовал ответ на этот вопрос, но я нашел лучшее решение.

Если вам просто нужно убедиться, что HWND создан, без фактического отображения окна, вы можете сделать это:

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

(на самом деле метод EnsureHandle недоступен, когда вопрос был опубликован, он был введен в .NET 4.0)

Ответ 5

Я никогда не пытался делать то, что вы делаете, но если вам нужно показать окно, чтобы получить HWND, но не хотите его показывать, установите Opacity Opacity равным 0. Это также предотвратит любой удар тестирование происходит. Тогда у вас может быть открытый метод в окне, чтобы изменить непрозрачность до 100, когда вы хотите сделать его видимым.

Ответ 6

Я ничего не знаю о WPF, но вы могли бы создать только окно сообщения, используя другие средства (например, PInvoke) для получения WM_HOTKEY сообщение? Если да, то после получения WM_HOTKEY вы можете запустить окно WPF.

Ответ 7

Класс WindowInteropHelper должен позволить вам получить HWND для окна WPF.

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

IntPtr hwnd = helper.Handle;

Документация MSDN

Ответ 8

Другим вариантом в аналогичном ключе для установки непрозрачности 0 является установка размера 0 и установка позиции на экране. Для этого не требуется AllowsTransparency = True.

Также помните, что как только вы показали его, как только сможете, спрячьте его и получите hwnd.

Ответ 9

Сделайте размер окна 0 x 0 px, поместите ShowInTaskBar в значение false, покажите его, а затем измените его размер по мере необходимости.

Ответ 10

Я создал метод расширения для отображения невидимого окна, следующие 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;
    }
}