Mettre à jour:
Selon @donovan, WPF moderne prend en charge cela de manière native, via la configuration
ShowInTaskbar="False"
et Visibility="Hidden"
dans le XAML. (Je n'ai pas encore testé cela, mais j'ai néanmoins décidé d'augmenter la visibilité des commentaires)
Réponse originale:
Il existe deux façons de masquer une fenêtre du sélecteur de tâches dans l'API Win32:
- pour ajouter le
WS_EX_TOOLWINDOW
style de fenêtre étendu - c'est la bonne approche.
- pour en faire une fenêtre enfant d'une autre fenêtre.
Malheureusement, WPF ne prend pas en charge un contrôle aussi flexible sur le style de fenêtre que Win32, donc une fenêtre avec WindowStyle=ToolWindow
se termine avec la valeur par défaut WS_CAPTION
et les WS_SYSMENU
styles, ce qui lui donne une légende et un bouton de fermeture. D'un autre côté, vous pouvez supprimer ces deux styles en définissant WindowStyle=None
, mais cela ne définira pas le WS_EX_TOOLWINDOW
style étendu et la fenêtre ne sera pas masquée du sélecteur de tâches.
Pour avoir une fenêtre WPF avec WindowStyle=None
qui est également masquée dans le sélecteur de tâches, vous pouvez de deux manières:
- allez avec l'exemple de code ci-dessus et faites de la fenêtre une fenêtre enfant d'une petite fenêtre d'outils cachée
- modifiez le style de fenêtre pour inclure également le
WS_EX_TOOLWINDOW
style étendu.
Personnellement, je préfère la deuxième approche. Là encore, je fais des choses avancées comme étendre la vitre dans la zone client et activer le dessin WPF dans la légende de toute façon, donc un peu d'interopérabilité n'est pas un gros problème.
Voici l'exemple de code pour l'approche de solution d'interopérabilité Win32. Tout d'abord, la partie 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" >
Rien d'extraordinaire ici, nous déclarons simplement une fenêtre avec WindowStyle=None
et ShowInTaskbar=False
. Nous ajoutons également un gestionnaire à l'événement Loaded où nous modifierons le style de fenêtre étendu. Nous ne pouvons pas faire ce travail dans le constructeur, car il n'y a pas encore de handle de fenêtre à ce stade. Le gestionnaire d'événements lui-même est très 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);
}
Et les déclarations d'interopérabilité Win32. J'ai supprimé tous les styles inutiles des énumérations, juste pour garder l'exemple de code ici petit. De plus, malheureusement, le SetWindowLongPtr
point d'entrée ne se trouve pas dans user32.dll sous Windows XP, d'où l'astuce consistant à acheminer l'appel via le 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