Actualizar:
Según @donovan, en la actualidad WPF admite esto de forma nativa, a través de la configuración
ShowInTaskbar="False"
y Visibility="Hidden"
en el XAML. (No he probado esto todavía, pero sin embargo decidí aumentar la visibilidad de los comentarios)
Respuesta original:
Hay dos formas de ocultar una ventana del conmutador de tareas en la API de Win32:
- para agregar el
WS_EX_TOOLWINDOW
estilo de ventana extendida, ese es el enfoque correcto.
- para convertirla en una ventana secundaria de otra ventana.
Desafortunadamente, WPF no admite un control tan flexible sobre el estilo de la ventana como Win32, por lo que una ventana WindowStyle=ToolWindow
termina con los estilos WS_CAPTION
y predeterminados WS_SYSMENU
, lo que hace que tenga un título y un botón de cierre. Por otro lado, puede eliminar estos dos estilos configurando WindowStyle=None
, sin embargo, eso no establecerá el WS_EX_TOOLWINDOW
estilo extendido y la ventana no se ocultará del selector de tareas.
Para tener una ventana de WPF WindowStyle=None
que también esté oculta en el selector de tareas, se puede de dos maneras:
- vaya con el código de muestra anterior y convierta la ventana en una ventana secundaria de una pequeña ventana de herramientas oculta
- modifique el estilo de la ventana para incluir también el
WS_EX_TOOLWINDOW
estilo extendido.
Personalmente prefiero el segundo enfoque. Por otra parte, hago algunas cosas avanzadas como extender el cristal en el área del cliente y habilitar el dibujo de WPF en el título de todos modos, por lo que un poco de interoperabilidad no es un gran problema.
Aquí está el código de muestra para el enfoque de la solución de interoperabilidad de Win32. Primero, la parte XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300"
ShowInTaskbar="False" WindowStyle="None"
Loaded="Window_Loaded" >
Nada demasiado sofisticado aquí, solo declaramos una ventana con WindowStyle=None
y ShowInTaskbar=False
. También agregamos un controlador al evento Loaded donde modificaremos el estilo de la ventana extendida. No podemos hacer ese trabajo en el constructor, ya que todavía no hay un identificador de ventana en ese punto. El controlador de eventos en sí es muy simple:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
WindowInteropHelper wndHelper = new WindowInteropHelper(this);
int exStyle = (int)GetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE);
exStyle |= (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW;
SetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
}
Y las declaraciones de interoperabilidad de Win32. He eliminado todos los estilos innecesarios de las enumeraciones, solo para mantener pequeño el código de muestra aquí. Además, desafortunadamente, el SetWindowLongPtr
punto de entrada no se encuentra en user32.dll en Windows XP, de ahí el truco de enrutar la llamada a través de SetWindowLong
.
#region Window styles
[Flags]
public enum ExtendedWindowStyles
{
// ...
WS_EX_TOOLWINDOW = 0x00000080,
// ...
}
public enum GetWindowLongFields
{
// ...
GWL_EXSTYLE = (-20),
// ...
}
[DllImport("user32.dll")]
public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
int error = 0;
IntPtr result = IntPtr.Zero;
// Win32 SetWindowLong doesn't clear error on success
SetLastError(0);
if (IntPtr.Size == 4)
{
// use SetWindowLong
Int32 tempResult = IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong));
error = Marshal.GetLastWin32Error();
result = new IntPtr(tempResult);
}
else
{
// use SetWindowLongPtr
result = IntSetWindowLongPtr(hWnd, nIndex, dwNewLong);
error = Marshal.GetLastWin32Error();
}
if ((result == IntPtr.Zero) && (error != 0))
{
throw new System.ComponentModel.Win32Exception(error);
}
return result;
}
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]
private static extern Int32 IntSetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);
private static int IntPtrToInt32(IntPtr intPtr)
{
return unchecked((int)intPtr.ToInt64());
}
[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
public static extern void SetLastError(int dwErrorCode);
#endregion