2010-07-10 14 views
7

Necesito acceder a los identificadores de ventana de Win32 de algunas de mis ventanas WPF para que pueda manejar los mensajes de activación de Win32. Sé que puedo usar PresentationSource.FromVisual o WindowInteropHelper para obtener el identificador de la ventana Win32, pero estoy teniendo problemas si todavía no se ha creado la ventana de WPF.Forzar la creación de un identificador Win32 nativo de WPF Window

Si uso PresentationSource.FromVisual y la ventana no se ha creado, el PresentationSource devuelto es nulo. Si utilizo WindowInteropHelper y la ventana no se ha creado, la propiedad Handle es IntPtr.Zero (nulo).

Intenté llamar a this.Show() y this.Hide() en la ventana antes de intentar acceder al identificador. Puedo obtener el asa, pero la ventana parpadea momentáneamente en la pantalla (¡feo!).

¿Alguien sabe de una manera de forzar que se cree una ventana de WPF? En Windows Forms, esto fue tan fácil como acceder a la propiedad Form.Handle.

Editar: Terminé yendo con una variante de la respuesta de Chris Taylor. Aquí está, en el caso de que ayuda a otra persona:

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); 
+0

¿Has visto esta pregunta - http://stackoverflow.com/questions/1556182/finding-the-handle-to-a-wpf-window? Podría no ser de ayuda, ya que no menciona si la ventana ya existe o no. – ChrisF

+0

@ChrisF: ¡Gracias! Sí, he visto eso. Desafortunadamente, todavía no se ha creado el problema con la ventana. –

+0

Pensé en mencionarlo para obtener su respuesta, de modo que si su caso fuera diferente, no fuera seleccionado como duplicado. – ChrisF

Respuesta

3

Una opción es establecer el estado de ventana minimizada y al no mostrar en la barra de tareas antes de mostrar la ventana. Prueba algo como esto.

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; 
+0

¡Gracias! Terminé yendo con una variante de esto (ver mi edición sobre la pregunta). –

+2

[@ DanielAlbuschat's answer] (http://stackoverflow.com/a/4826741/24874) es más simple y evita el parpadeo. –

+0

Sí, la respuesta a continuación es mucho más clara. –

17

Use WindowInteropHelper.EnsureHandle, hace exactamente lo que necesita.

+0

+1 ¡Gran hallazgo! Tendré que probarlo. –

+0

¡Tengo el mismo problema, y ​​esta es la mejor respuesta! – laishiekai

+0

Una vez más, ¡esta es una respuesta mucho mejor que la aceptada! Por favor use esto en cambio, ¡todos! –

2

Estaba buscando una solución si el identificador de WindowInteropHelper es NULL. Esperemos que esta publicación proporcione información adicional sobre cómo resolverlo.

Una solución es utilizar:

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

esto sólo funciona con .NET Framework 4.

Por el momento estoy usando .NET Framework 3.5, así que necesitaba otra solución. Entonces me encontré con un hilo del foro con un método de extensión 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; 
     } 
    } 
} 

El WindowInteropHelper.EnsureHandle() no espera una ventana ya está creado.

Referencia: Alexander Yudakov - http://social.msdn.microsoft.com/Forums/en-MY/wpf/thread/5f89ac58-d2ef-4ac0-aefb-b2826dbef48a

0

me he quedado atrapado en este mismo tema y fui con J Pollack's answer (porque parece más limpio para mí), pero necesitaba algo que podría funcionar tanto en el tiempo de ejecución de .NET 2.0 y 4.0.

Pero cuando hice eso terminé con un feo MissingMethodException porque SafeCreateWindow no existe en el tiempo de ejecución .NET 4.0 más. Para que el código en ambos tiempos de ejecución que decidí coger el MissingMethodException e invocar el equivalente en el tiempo de ejecución .NET 4.0 en vez de esta manera:

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; 
    } 

Esto me permitió compilar el código con .NET 3.5, pero ejecuto en .NET runtime 4.0 en sistemas que solo tienen instalada la versión de tiempo de ejecución más alta (es decir, Windows 8 y superior).

Cuestiones relacionadas