更新:
根据@donovan 的说法,现代 WPF 通过设置
ShowInTaskbar="False"
和Visibility="Hidden"
在 XAML 中本机支持这一点。(我还没有对此进行测试,但仍然决定提高评论的可见性)
原答案:
在 Win32 API 中,有两种方法可以从任务切换器中隐藏窗口:
- 添加
WS_EX_TOOLWINDOW
扩展窗口样式 - 这是正确的方法。
- 使其成为另一个窗口的子窗口。
不幸的是,WPF 不像 Win32 那样支持对窗口样式的灵活控制,因此窗口以WindowStyle=ToolWindow
默认WS_CAPTION
和WS_SYSMENU
样式结束,这导致它具有标题和关闭按钮。另一方面,您可以通过设置删除这两种样式WindowStyle=None
,但这不会设置WS_EX_TOOLWINDOW
扩展样式,并且窗口不会从任务切换器中隐藏。
要使 WPF 窗口WindowStyle=None
也从任务切换器中隐藏,可以采用以下两种方式之一:
- 使用上面的示例代码,使窗口成为一个小隐藏工具窗口的子窗口
- 修改窗口样式以包括
WS_EX_TOOLWINDOW
扩展样式。
我个人更喜欢第二种方法。再说一次,我做了一些高级的事情,比如在客户区扩展玻璃并在标题中启用 WPF 绘图,所以一点互操作不是一个大问题。
这是 Win32 互操作解决方案方法的示例代码。首先,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" >
这里没什么花哨的,我们只是用WindowStyle=None
and声明一个窗口ShowInTaskbar=False
。我们还向 Loaded 事件添加了一个处理程序,我们将在其中修改扩展窗口样式。我们不能在构造函数中完成这项工作,因为此时还没有窗口句柄。事件处理程序本身非常简单:
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);
}
和 Win32 互操作声明。我已经从枚举中删除了所有不必要的样式,只是为了保持这里的示例代码很小。此外,不幸的SetWindowLongPtr
是,在 Windows XP 上的 user32.dll 中没有找到入口点,因此通过路由调用的技巧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