Принудительное создание дескриптора Win32 Windows WPF Window - PullRequest
9 голосов
/ 10 июля 2010

Мне нужен доступ к дескрипторам окон Win32 некоторых из моих окон WPF, чтобы я мог обрабатывать сообщения активации Win32.Я знаю, что могу использовать PresentationSource.FromVisual или WindowInteropHelper, чтобы получить дескриптор окна Win32, но у меня возникают проблемы, если окно WPF еще не создано.

Если я использую PresentationSource.FromVisual и окноне был создан, возвращенное значение PresentationSource равно нулю.Если я использую WindowInteropHelper и окно не было создано, свойство Handle имеет значение IntPtr.Zero (ноль).

Я пытался вызвать this.Show() и this.Hide() в окне, прежде чем пыталсяполучить доступ к ручке.Затем я могу получить ручку, но окно на мгновение мигает на экране (некрасиво!).

Кто-нибудь знает способ заставить окно WPF быть созданным?В Windows Forms это было так же просто, как получить доступ к свойству Form.Handle.

Редактировать: В итоге я выбрал вариант ответа Криса Тейлора.Вот, если это кому-то поможет:

static void InitializeWindow(Window window)
{
    // Get the current values of the properties we are going to change
    double oldWidth = window.Width;
    double oldHeight = window.Height;
    WindowStyle oldWindowStyle = window.WindowStyle;
    bool oldShowInTaskbar = window.ShowInTaskbar;
    bool oldShowActivated = window.ShowActivated;

    // Change the properties to make the window invisible
    window.Width = 0;
    window.Height = 0;
    window.WindowStyle = WindowStyle.None;
    window.ShowInTaskbar = false;
    window.ShowActivated = false;

    // Make WPF create the window's handle
    window.Show();
    window.Hide();

    // Restore the old values
    window.Width = oldWidth;
    window.Height = oldHeight;
    window.WindowStyle = oldWindowStyle;
    window.ShowInTaskbar = oldShowInTaskbar;
    window.ShowActivated = oldShowActivated;
}

// Use it like this:
InitializeWindow(myWpfWindow);

Ответы [ 4 ]

21 голосов
/ 28 января 2011

Используйте WindowInteropHelper.EnsureHandle, он делает именно то, что вам нужно.

3 голосов
/ 12 августа 2011

Я искал решение, если дескриптор WindowInteropHelper имеет значение NULL. Надеемся, что этот пост дает дополнительную информацию о том, как ее решить.

Одним из решений является использование:

var window = new Window();
var handle = new WindowInteropHelper(window).EnsureHandle()

Это работает только с .NET Framework 4.

В настоящее время я использую .NET Framework 3.5, поэтому мне нужно было другое решение. Затем я нашел ветку форума с методом расширения WindowInteropHelper:

#region

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Interop;

#endregion

namespace System.Windows.Interop
{
    /// <summary>
    ///   Provides NetFX 4.0 EnsureHandle method for
    ///   NetFX 3.5 WindowInteropHelper class.
    /// </summary>
    public static class WindowInteropHelperExtension
    {
        /// <summary>
        ///   Creates the HWND of the window if the HWND has not been created yet.
        /// </summary>
        /// <param name = "helper">An instance of WindowInteropHelper class.</param>
        /// <returns>An IntPtr that represents the HWND.</returns>
        /// <remarks>
        ///   Use the EnsureHandle method when you want to separate
        ///   window handle (HWND) creation from the
        ///   actual showing of the managed Window.
        /// </remarks>
        public static IntPtr EnsureHandle(this WindowInteropHelper helper)
        {
            if (helper == null)
                throw new ArgumentNullException("helper");

            if (helper.Handle == IntPtr.Zero)
            {
                var window = (Window) typeof (WindowInteropHelper).InvokeMember(
                    "_window",
                    BindingFlags.GetField |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, helper, null);

                typeof (Window).InvokeMember(
                    "SafeCreateWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, null);
            }

            return helper.Handle;
        }
    }
}

WindowInteropHelper.EnsureHandle () не ожидает, что окно уже создано.

Ссылка: Александр Юдаков - http://social.msdn.microsoft.com/Forums/en-MY/wpf/thread/5f89ac58-d2ef-4ac0-aefb-b2826dbef48a

3 голосов
/ 10 июля 2010

Один из вариантов - установить минимизированное состояние окна и не отображать его на панели задач перед отображением окна. Попробуйте что-то вроде этого.

  IntPtr hWnd;
  WindowInteropHelper helper = new WindowInteropHelper(wnd);

  WindowState prevState = wnd.WindowState;
  bool prevShowInTaskBar = wnd.ShowInTaskbar;

  wnd.ShowInTaskbar = false;
  wnd.WindowState = WindowState.Minimized;
  wnd.Show();
  hWnd = helper.Handle;
  wnd.Hide();

  wnd.ShowInTaskbar = prevShowInTaskBar;
  wnd.WindowState = prevState;
1 голос
/ 24 октября 2014

Я застрял в этой же проблеме и продолжил с J Ответом Поллака (потому что он мне кажется чище), но мне нужно что-то, что могло бы работать как в среде выполнения .NET 2.0, так и в 4.0.

Но когда я это сделал, у меня получилось ужасное MissingMethodException , потому что SafeCreateWindow больше не существует в среде выполнения .NET 4.0. Чтобы заставить код работать в обеих средах выполнения, я решил перехватить исключение MissingMethodException и вместо этого вызвать эквивалент в среде выполнения .NET 4.0, например:

    public static IntPtr EnsureHandle(this WindowInteropHelper helper)
    {
        if (helper == null)
            throw new ArgumentNullException("helper");

        if (helper.Handle == IntPtr.Zero)
        {
            var window = (Window)typeof(WindowInteropHelper).InvokeMember(
                "_window",
                BindingFlags.GetField |
                BindingFlags.Instance |
                BindingFlags.NonPublic,
                null, helper, null);

            try
            {
                // SafeCreateWindow only exists in the .NET 2.0 runtime. If we try to
                // invoke this method on the .NET 4.0 runtime it will result in a
                // MissingMethodException, see below.
                typeof(Window).InvokeMember(
                    "SafeCreateWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, null);
            }
            catch (MissingMethodException)
            {
                // If we ended up here it means we are running on the .NET 4.0 runtime,
                // where the method we need to call for the handle was renamed/replaced
                // with CreateSourceWindow.
                typeof(Window).InvokeMember(
                    "CreateSourceWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, new object[] { false });
            }
        }

        return helper.Handle;
    }

Это позволило мне скомпилировать код с помощью .NET 3.5, но запустить его в .NET runtime 4.0 в системах, в которых установлена ​​только более поздняя версия (а именно Windows 8 и выше).

...