我一直是一个好朋友.NET开发者已经有好几年了,这仍然是我不知道如何正确处理的事情之一.通过Windows窗体和WPF中的属性可以很容易地从任务栏隐藏窗口,但据我所知,这并不保证(甚至不一定会影响)它被隐藏在Alt+↹选项卡对话框.我在Alt中看到了invisible个窗口↹Tab,我只是想知道什么是保证窗口在Alt+中出现(可见或不可见)的最佳方法↹选项卡对话框.

Update:请看下面我发布的解决方案.我不允许将自己的答案标记为解决方案,但到目前为止,这是唯一有效的解决方案.

弗朗西·佩诺夫(Franci Penov)现在有一个合适的解决方案,看起来相当不错,但我自己还没有试过.涉及到一些Win32,但避免了屏幕外窗口的创建过程.

推荐答案

Update:

根据@Donovan的说法,现代的WPF通过设置 XAML中的ShowInTaskbar="False"Visibility="Hidden".(我还没有测试这一点,但仍然决定提高 comments 的可见性)

Original answer:

在Win32 API中,有两种方法可以对任务切换器隐藏窗口:

  1. 添加WS_EX_TOOLWINDOW个扩展窗口样式——这是正确的方法.
  2. 让它成为另一个窗口的子窗口.

不幸的是,WPF不支持像Win32那样灵活地控制窗口样式,因此一个有WindowStyle=ToolWindow个窗口的窗口最终会有默认的WS_CAPTIONWS_SYSMENU样式,这导致它有一个标题和一个关闭按钮.另一方面,您可以通过设置WindowStyle=None来删除这两种样式,但是这不会设置WS_EX_TOOLWINDOW扩展样式,窗口也不会对任务切换程序隐藏.

要使WindowStyle=None的WPF窗口也对任务切换器隐藏,可以采用以下两种方式之一:

  • 使用上面的示例代码,并使该窗口成为一个隐藏的小工具窗口的子窗口
  • 修改窗样式,使其也包括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=NoneShowInTaskbar=False.我们还向加载的事件添加了一个处理程序,我们将在其中修改扩展窗口样式.我们不能在构造函数中完成这项工作,因为此时还没有窗口句柄.事件处理程序本身非常简单:

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互操作声明.我已经从枚举中删除了所有不必要的样式,只是为了保持这里的示例代码较小.此外,不幸的是,在user32中找不到SetWindowLongPtr入口点.Windows XP上的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

.net相关问答推荐

PowerShell 5.1和7在使用证书时的区别

竖线在 PropertyGroup .csproj 文件中的含义

如何使用 Moq 为不同的参数设置两次方法

为什么 C# 不允许像 C++ 这样的非成员函数

BackgroundWorker 中未处理的异常

为什么字典比列表快得多?

什么是编组?当某些东西被编组时会发生什么?

支持 HTTPS 的 Httplistener

如何将 UI Dispatcher 传递给 ViewModel

HashSet 是否保留插入顺序?

C# 属性实际上是方法吗?

变量MyException已声明但从未使用

在 C# 中将字符串转换为十六进制字符串

从 C# 中的接口继承 XML 注释

System.Speech.Recognition 和 Microsoft.Speech.Recognition 有什么区别?

什么是 C# 中的自动属性,它们的用途是什么?

如何使用 C# 创建自签名证书?

如何使用 Entity Framework Code First CTP 5 存储图像?

为什么 double.NaN 不等于自身?

Microsoft.Bcl.Build NuGet 包有什么作用?