隐藏WPF窗口中的图标

8
我知道有很多问题涉及隐藏或删除WPF窗口左上角的图标,也就是系统菜单所在的位置。我尝试了很多方法,但都无效。以下是我的要求:
  • 图标消失且不占据任何空白空间(即没有透明图标)
  • 窗口标题直接从窗口左边缘开始
  • 右上角的关闭按钮仍然存在并且有效
  • 如果启用,则最小化/最大化按钮仍然存在(可选,未测试)
  • 没有自定义绘制整个窗口框架
  • 在启用Aero Glass的Windows 7上工作(Windows 8呢?)
  • 在32位和64位Windows上工作(x86和x64版本)
  • 使用WPF .NET 4.0
  • 在不像Visual Studio那样处于调试器中时也可以工作(如果在调试器中也可以工作则更好)
  • 应该也可以在Windows XP上工作(可选)

现有的答案基本上使用Windows API函数GetWindowLongSetWindowLong,有时还会使用SetWindowPos来添加扩展窗口样式WS_EX_DLGMODALFRAME并调用SWP_FRAMECHANGED。有时还会设置或取消其他样式。

不幸的是,这些都根本不起作用。我要么没有图标和关闭按钮,要么两者都在那里。但是值得注意的是,所有这些内容都来自2010年或更早的时间。它似乎针对早期的.NET或Windows版本,因此失败了。

我已经使用Microsoft Spy++(包含在Visual Studio中)比较了系统对话框(来自资源管理器)和我的WPF窗口的窗口样式。但是,我可以尝试将所有标志设置为相同,但图标不会消失。就像黑魔法一样,它可以覆盖每个其他API函数或物理功能。

有没有人有一个在今天和指定环境下仍然有效的解决方案?


1
可能是从WPF窗口中删除图标的重复问题。 - Gayot Fow
3个回答

23

如果你只是像我一样把标题中的词汇输入到搜索引擎中,而不是在这里发问,那么你将会找到比这更多的结果。你可以在以下链接中找到答案:

从WPF窗口中删除图标

如何在标题栏中不显示wpf窗口的图标?

如何删除WPF窗口的图标

如何从窗口标题栏中删除图标

如何在WPF中隐藏窗口图标


你最后一条评论让我想起一些问题。于是,我将这段代码添加到了一个大型的应用程序中,并且它依然能够正常工作。然而,我继续测试了一下,你必须在应用程序中使用RibbonWindow,因为当我在一个带有RibbonWindow的大型应用程序上测试这段代码时,它就无法正常工作。

如果你正在使用普通的Window,请尝试使用以下代码(来自于第一个链接帖子中@MichalCiechan的答案):

首先添加以下类:

public static class IconHelper
{
    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hwnd, int index);

    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

    [DllImport("user32.dll")]
    static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, 
int y, int width, int height, uint flags);

    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr 
lParam);

    const int GWL_EXSTYLE = -20;
    const int WS_EX_DLGMODALFRAME = 0x0001;
    const int SWP_NOSIZE = 0x0001;
    const int SWP_NOMOVE = 0x0002;
    const int SWP_NOZORDER = 0x0004;
    const int SWP_FRAMECHANGED = 0x0020;
    const uint WM_SETICON = 0x0080;

    public static void RemoveIcon(Window window)
    {
        // Get this window's handle
        IntPtr hwnd = new WindowInteropHelper(window).Handle;
        // Change the extended window style to not show a window icon
        int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
        SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
        // Update the window's non-client area to reflect the changes
        SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | 
SWP_NOZORDER | SWP_FRAMECHANGED);
    }
}

然后将下面的内容添加到MainWindow.xaml.cs中:

protected override void OnSourceInitialized(EventArgs e)
{
    IconHelper.RemoveIcon(this);
}

哦……还有一件事要注意……如果您设置了 Window.Icon 属性,它将无法正常工作,但我猜您没有这样做,因为您不想显示图标。


2
抱歉,我已经看过所有的内容,但都没有用。从你的回答中,我看出你没有读懂我的问题,尤其是没有验证这些建议是否有效。 - ygoe
1
奇怪。那为什么在我的情况下不起作用呢?也许我应该添加另一个重要的要求:在非空窗口和存在多个窗口的实际应用程序中工作,而不仅仅是在测试用例中。如果这有所帮助的话。 - ygoe
3
也许 Sheridan 应该编辑第一句话 - 粗鲁的风格对于未来使用谷歌搜索到这里的读者是必要的。 - Robin
2
我发现了一个区别:只要我的.exe文件包含图标资源,该图标就会在窗口中使用。如果我将项目设置保留为“默认图标”,并且不向我的.exe文件添加其他非托管图标,则它可以正常工作。但是一旦有单个图标存在,它就会被显示出来。 - ygoe
6
如果你刚才把标题中的词放入搜索引擎中,而不是像我刚才在这里做的那样,那么你会找到比这更多的结果。尽管当时可能有用,但我觉得它现在已经不再相关了。我在谷歌上使用了短语“隐藏WPF窗口的图标”,第一个匹配项就落在了这里。考虑删除那个第一句话。 - user585968
这个问题现在出现在搜索结果中是无关紧要的...任何使用标题中的单词进行搜索的人仍然会找到比这里显示的更多的结果 - Sheridan

14

1
谢谢,这确实有效。似乎需要避免使用.exe图标资源。请参见我在另一个答案中的评论。 - ygoe
当在MPF项目系统中使用时,上述代码会移除默认的进程图标(VS2013),但会留下一个通用图标。 - user585968
非常感谢!我遇到了这样一个问题,当我使用调试器启动应用程序时,图标被正确地删除了,但是在没有调试器的情况下启动发布版本时却没有被删除。你的解决方案解决了这个问题! - JanDotNet
微软已删除了所有的Connect内容。这些SendMessage行应该放在哪里? - Jonathan Gilbert

2

在看到不同的解决方案后,我想出了以下解决方法:

    internal const int SWP_NOSIZE = 0x0001;
    internal const int SWP_NOMOVE = 0x0002;
    internal const int SWP_NOZORDER = 0x0004;
    internal const int SWP_FRAMECHANGED = 0x0020;
    internal const int GWL_EXSTYLE = -20;
    internal const int WS_EX_DLGMODALFRAME = 0x0001;

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    [DllImport("user32.dll")]
    internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    [DllImport("user32.dll")]
    internal static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);

    /// <summary>
    /// Hides icon for window.
    /// If this is called before InitializeComponent() then the icon will be completely removed from the title bar
    /// If this is called after InitializeComponent() then an empty image is used but there will be empty space between window border and title
    /// </summary>
    /// <param name="window">Window class</param>
    internal static void HideIcon(this Window window)
    {
        if (window.IsInitialized)
        {
            window.Icon = BitmapSource.Create(1, 1, 96, 96, PixelFormats.Bgra32, null, new byte[] {0, 0, 0, 0}, 4);
        }
        else
        {
            window.SourceInitialized += delegate
            {
                // Get this window's handle
                var hwnd = new WindowInteropHelper(window).Handle;

                // Change the extended window style to not show a window icon
                int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
                SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);

                // Update the window's non-client area to reflect the changes
                SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
            };
        }
    }

例子:

public partial class ExampleWindow : Window
{
    public ExampleWindow()
    {
        // Hides icon completely
        this.HideIcon();

        InitializeComponent();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接