从WPF窗口中删除图标

24
我能够使用 WinApi 删除 WPF 窗口的窗口图标,但是当我运行 WPF 项目的可执行文件时,应用程序窗口中又会出现图标。如何去掉这个图标?

2
WPF窗口和应用程序窗口有什么区别? - Timores
是的,请先接受之前问题的答案。 - Michal Ciechan
@LdnCobra,非常好的回答,但你没有给shraddha一个接受旧问题答案的动力 :-) - Timores
我不知道如何接受答案...我找不到直接接受答案的链接...而且我也看不到之前的答案... - shraddha
只需单击已帮助您的答案上的复选框。 - Michal Ciechan
@shraddha:请使用答案旁边的“勾”图标来接受答案。http://sstatic.net/so/img/vote-accepted.png - Thomas Levesque
6个回答

27

来自WPFTutorial

如何移除WPF窗口的图标

alt text

不幸的是,WPF并没有提供任何方法来移除窗口的图标。一个解决方案可以是将图标设置为透明的图标。但是这样窗口边框和标题之间的额外空间仍然存在。

更好的方法是使用Win32 API提供的函数来移除图标。

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

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

一个辅助类,用于移除图标。

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);
    }
}

4
同样的代码,当我仅使用exe运行项目时,它无法从窗口中移除图标。这时我没有使用Visual Studio来运行项目。 - shraddha
我的问题是它正在附加一个全新的图标到exe文件上,但这个图标会被删除。 - shraddha
我发现如果在Windows 7中禁用了Aero,或者在Windows XP(和我猜测的Windows 2003)上运行应用程序,则此解决方案无法正常工作。 - jmatthias
4
是的,修复方法是在底部添加以下代码行:SendMessage(hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero); - Mike Blandford
1
你可以添加 SWP_NOACTIVATE(0x0010) 标志来防止窗口在使用 SetWindowPos 函数时被激活。 - ghord
显示剩余2条评论

23

只需将WindowStyle="ToolWindow"添加到您的窗口属性中即可。


3
还不错。但这也隐藏了最大化/最小化按钮。 - Carlos Borau
1
哇,我从来不知道这件事情这么容易!但是在任务栏上会是什么样子呢? - mekb
1
这个可以工作,但会使窗口的关闭 X 变成红色! - Nandostyle

15

我已经修改了来自“LnDCobra”的示例,以便它可以用作附加属性(如“Thomas”建议的那样):

<Window 
        ...
        xmlns:i="clr-namespace:namespace-to-WindowEx"
        i:WindowEx.ShowIcon = "false"
        ...
>

WindowEx的实现:

public class WindowEx
  {
    private const int GwlExstyle = -20;
    private const int SwpFramechanged = 0x0020;
    private const int SwpNomove = 0x0002;
    private const int SwpNosize = 0x0001;
    private const int SwpNozorder = 0x0004;
    private const int WsExDlgmodalframe = 0x0001;

    public static readonly DependencyProperty ShowIconProperty =
      DependencyProperty.RegisterAttached(
        "ShowIcon",
        typeof (bool),
        typeof (WindowEx),
        new FrameworkPropertyMetadata(true, new PropertyChangedCallback((d, e) => RemoveIcon((Window) d))));


    public static Boolean GetShowIcon(UIElement element)
    {
      return (Boolean) element.GetValue(ShowIconProperty);
    }

    public static void RemoveIcon(Window window)
    {
      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, GwlExstyle);
        SetWindowLong(hwnd, GwlExstyle, extendedStyle | WsExDlgmodalframe);

        // Update the window's non-client area to reflect the changes
        SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SwpNomove |
          SwpNosize | SwpNozorder | SwpFramechanged);
      };
    }

    public static void SetShowIcon(UIElement element, Boolean value)
    {
      element.SetValue(ShowIconProperty, value);
    }

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

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

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

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

5
在调试模式下,这对我来说运行得很好,但如果我在非调试环境下运行它,则不起作用。 - Christoph Meißner
被接受的答案在.NET4.5中不起作用,而您的答案对我有用。谢谢!无论是在Visual Studio的调试模式下还是通过从Windows资源管理器运行exe文件,都可以正常工作。 - sudarsanyes
1
当我将这个答案与https://dev59.com/UHbZa4cB1Zd3GeqPFWQA相结合时,它在.NET4.5中对我有效。此外,XAML设计器抱怨无法将WindowsInstance转换为Window,因此我不得不稍微重写它并删除对窗口的直接转换:`PropertyChangedCallback((d, e) => RemoveIcon((Window) d)`; - username

11

以下是一个简单而纯粹的XAML解决方案:

<Window x:Class="...">

    <Window.Icon>
        <DrawingImage />
    </Window.Icon>

    ...

</Window>

5
这应该是被接受的答案。标题当然是被空图标推动的,但这只是一个小代价。我只是讨厌为了删除一个图标而搞乱Windows DLL! - Nandostyle
1
这似乎使任务栏图标变为空白。 - Vultuxe

7

我只是在WPF窗口中使用了一个非常小的透明图像作为图标(1x1像素)。


2
创建一个透明的1x1图标,并将其替换为标准图标。
Icon = BitmapSource.Create(1, 1, 0, 0, PixelFormats.Bgra32, null, new byte[4], 4);

请问您可以扩展您的答案吗? - Mate

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