La conexión al bucle de mensajes de Windows en la ventana de WPF agrega un borde blanco en el interior

Estoy intentando crear una ventana de WPF con WindowStyle="None" (para botones personalizados y sin título) que no se puede cambiar de tamaño. La configuración de ResizeMode en NoResize elimina el borde aero, que deseo mantener.

Podría establecer las propiedades de tamaño mínimo / máximo y terminar con eso, excepto que:

  1. Los cursores de redimensionamiento siguen siendo visibles, y
  2. La ventana se muestra en respuesta a una acción del usuario y se ajusta a su contenido. Muestra una imagen, por lo que el tamaño cambia.

Entonces, tengo un esquema simple que me lleva al 99% del camino:

 public class BorderedWindowNoResize : Window { [DllImport( "DwmApi.dll" )] public static extern int DwmExtendFrameIntoClientArea( IntPtr hwnd, ref MARGINS pMarInset ); [DllImport( "user32.dll", CharSet = CharSet.Auto )] public static extern IntPtr DefWindowProc( IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam ); public BorderedWindowNoResize() { Loaded += BorderedWindowNoResize_Loaded; } private void BorderedWindowNoResize_Loaded( object sender, RoutedEventArgs e ) { IntPtr mainWindowPtr = new WindowInteropHelper( this ).Handle; HwndSource mainWindowSrc = HwndSource.FromHwnd( mainWindowPtr ); mainWindowSrc.AddHook( WndProc ); } private IntPtr WndProc( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) { var htLocation = DefWindowProc( hwnd, msg, wParam, lParam ).ToInt32(); if( msg == (uint)WM.NCHITTEST ) { handled = true; switch( htLocation ) { case (int)HitTestResult.HTBOTTOM: case (int)HitTestResult.HTBOTTOMLEFT: case (int)HitTestResult.HTBOTTOMRIGHT: case (int)HitTestResult.HTLEFT: case (int)HitTestResult.HTRIGHT: case (int)HitTestResult.HTTOP: case (int)HitTestResult.HTTOPLEFT: case (int)HitTestResult.HTTOPRIGHT: htLocation = (int)HitTestResult.HTBORDER; break; } } return new IntPtr( htLocation ); } } 

Básicamente;

  1. Anular el procedimiento de ventana.
  2. Llame al procedimiento de ventana por defecto.
  3. Si el mensaje es WM_NCHITTEST , verifique los resultados del borde.
  4. Si es un borde, devuelve el HTBORDER regular.

Esto me permite mantener el borde de la ventana aerodinámica y ocultar el (los) cursor (s) de tamaño, pero agrega un borde blanco de ~ 5 píxeles al interior de mi ventana.

De hecho, incluso si devuelvo el resultado del procedimiento de Windows predeterminado en la parte superior de WndPrc y no hago nada más, el borde todavía está allí. Necesito un color de fondo diferente en mi ventana, así que esto no funcionará para mí.

¿Algunas ideas? Gracias de antemano, como siempre.

Cuando agrega su gancho, solo debe manejar los mensajes que necesita e ignorar los demás. Creo que está manejando ciertos mensajes dos veces, ya que llama a DefWindowProc, pero nunca establece el parámetro manejado en verdadero.

Así que en tu caso, usarías:

 private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == (uint)WM.NCHITTEST) { handled = true; var htLocation = DefWindowProc(hwnd, msg, wParam, lParam).ToInt32(); switch (htLocation) { case (int)HitTestResult.HTBOTTOM: case (int)HitTestResult.HTBOTTOMLEFT: case (int)HitTestResult.HTBOTTOMRIGHT: case (int)HitTestResult.HTLEFT: case (int)HitTestResult.HTRIGHT: case (int)HitTestResult.HTTOP: case (int)HitTestResult.HTTOPLEFT: case (int)HitTestResult.HTTOPRIGHT: htLocation = (int)HitTestResult.HTBORDER; break; } return new IntPtr(htLocation); } return IntPtr.Zero; } 

Además, probablemente agregaría el gancho en una anulación OnSourceInitialized , de esta manera:

 protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle; HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr); mainWindowSrc.AddHook(WndProc); } 

Puedes probar desde cualquier lugar en una aplicación WPF

  ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage); 

y:

  // ****************************************************************** private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled) { if (!handled) { if (msg.message == WmHotKey) { HotKey hotKey; if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey)) { if (hotKey.Action != null) { hotKey.Action.Invoke(hotKey); } handled = true; } } } } 

Espero eso ayude… 🙂