Update:
According to @donovan, these days WPF supports this initially by setting ShowInTaskbar="False" and Visibility="Hidden" in XAML. (I have not tested this yet, but nevertheless decided to emphasize the visibility of the comment)
Original answer:
There are two ways to hide the window from the task switcher in the Win32 API:
- add style
WS_EX_TOOLWINDOW extended window - the right approach. - to make it a child window of another window.
Unfortunately, WPF does not support flexible control over the window style as Win32, so the window with WindowStyle=ToolWindow ends with the default styles WS_CAPTION and WS_SYSMENU , which forces it to have a signature and close the button. On the other hand, you can remove these two styles by setting WindowStyle=None , however this will not set the extended style to WS_EX_TOOLWINDOW , and the window will not be hidden from the task switcher.
To have a WPF window with WindowStyle=None , which is also hidden from the task switcher, you can use one of two ways:
- go with the code example above and make the window a child window of a small hidden tool window
- change the window style to include the advanced style
WS_EX_TOOLWINDOW .
I personally prefer the second approach. Again, I am doing some advanced things, such as expanding the glass in the client area and including the WPF drawing in the signature anyway, so a bit of interaction is not a big problem.
Here is a sample code to solve the Win32 interop solution. First, part of 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" >
Nothing special here, we just declare a window with WindowStyle=None and ShowInTaskbar=False . We also add a Loaded event handler, where we will change the extended window style. We cannot do this work in the constructor, because at this moment there is no window handle. The event handler itself is very 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); }
And Win32 interop announcements. I removed all unnecessary styles from the enumerations in order to save the sample code here. Unfortunately, the SetWindowLongPtr entry SetWindowLongPtr not found in user32.dll in Windows XP, hence the trick of routing the call through 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