如何隐藏WPF窗口图标并使用ResizeMode=NoResize?

问题描述 投票:0回答:2

我最近实现了这个问题中的解决方案来隐藏 WPF 窗口的图标。我发现当该解决方案与

ResizeMode=NoResize
结合使用时,应用程序的标题栏上下文菜单无法禁用最小/最大/调整大小选项。

奇怪的是,上下文菜单并没有错误地启用某些选项,它只是保留了隐藏图标之前上下文菜单的状态。我使用一个简单的测试应用程序发现了这一点,该应用程序可以进行必要的调用来隐藏图标,并且可以动态更新窗口的

ResizeMode

图标显示,ResizeMode=CanResize

标题栏按钮和上下文菜单正确。

图标隐藏,ResizeMode=可以调整大小

还是正确的

图标隐藏,ResizeMode=NoResize

标题栏按钮已正确隐藏,但上下文菜单保留其先前的状态。如果我切换到

CanMinimize
,然后切换到
NoResize
,上下文菜单将仅启用“最小化”。

当可调整大小的 WPF 窗口启动另一个设置为

NoResize
的窗口(并且您隐藏了该图标)时,这会成为问题。

问题

是否有其他 Windows API 函数可以强制上下文菜单重新评估其状态?那么

NoResize
选项可能会导致这种奇怪的行为吗?由于这仅影响
NoResize
选项,WPF 级别是否有解决方法?

编辑 - 我的目标是避免使用

WindowStyle=ToolWindow
WS_EX_TOOLWINDOW
扩展窗口样式。我过去发现了该窗口样式的一些问题,其中一个被描述为on this question。我使用整个方法的目标之一是模拟
ToolWindow
的外观,而无需实际使用它。

c# wpf
2个回答
1
投票

使用.NET 4.0和Windows 8.1 Enterprise(我不知道它是否适用于其他.NET版本或不同的操作系统),您只需要使用

WS_EX_TOOLWINDOW
扩展样式而不是
WS_EX_DLGMODALFRAME
样式即可。

所以代码将是:

public partial class MainWindow : Window
{
    [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);

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

    public MainWindow()
    {
        InitializeComponent();
        ResizeMode = System.Windows.ResizeMode.NoResize;
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        IntPtr hwnd = new WindowInteropHelper(this).Handle;

        int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
        SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW);

        SendMessage(hwnd, WM_SETICON, new IntPtr(1), IntPtr.Zero);
        SendMessage(hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero);

        SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | 
            SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
    }
}

希望能帮到你。


0
投票

我知道这是一个老问题,但我前段时间也遇到过这个问题。 因此,如果您不想使用 WS_EX_TOOLWINDOW,这对您来说可能是一个很好的解决方案。 隐藏图标后,您应该只显示灰色上下文菜单的项目。

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

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

    [DllImport("user32.dll")]
    private static extern Boolean SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, Int32 x, Int32 y, Int32 width, Int32 height, UInt32 flags);

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

    private const Int32 GWL_EXSTYLE = -20;
    private const Int32 WS_EX_DLGMODALFRAME = 0x0001;
    
    private const Int32 SWP_NOSIZE = 0x0001;
    private const Int32 SWP_NOMOVE = 0x0002;
    private const Int32 SWP_NOZORDER = 0x0004;
    private const Int32 SWP_FRAMECHANGED = 0x0020;
    
    private const UInt32 WM_SETICON = 0x0080;
    private const Int32 ICON_SMALL = 0;
    private const Int32 ICON_BIG = 1;
    
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, Boolean bRevert);
    
    [DllImport("user32.dll", EntryPoint = "EnableMenuItem")] 
    private static extern IntPtr EnableMenuItem(IntPtr hMenu, UInt32 uIDEnableItem, UInt32 uEnable);
    
    private const Int32 SC_MAXIMIZE = 0xF030;
    private const Int32 SC_MINIMIZE = 0xF020;
    private const Int32 SC_SIZE = 0xF000;
    private const Int32 SC_RESTORE = 0xF120;
    
    private const UInt32 MF_BYCOMMAND = 0x00000000;
    private const UInt32 MF_DISABLED = 0x00000002;
    private const UInt32 MF_GRAYED = 0x00000001;

private void RemoveUpperLeftCornerIcon()
{
    IntPtr hwnd = new WindowInteropHelper(this).EnsureHandle();
    UInt32 extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE); 
   
    //set a new style to be able to hide the icon  
    SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
    
    //hide icon
    SendMessage(hwnd, WM_SETICON, (IntPtr)ICON_SMALL, IntPtr.Zero);
    SendMessage(hwnd, WM_SETICON, (IntPtr)ICON_BIG, IntPtr.Zero);
    
    //inform about changes
    SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);

    if (this.ResizeMode == ResizeMode.NoResize)
    {
        //gray context menu's items related to size (because WS_EX_DLGMODALFRAME breaks it)
        IntPtr hSystemMenu = GetSystemMenu(hwnd, false);
        EnableMenuItem(hSystemMenu, SC_MAXIMIZE, MF_GRAYED | MF_BYCOMMAND);
        EnableMenuItem(hSystemMenu, SC_MINIMIZE, MF_GRAYED | MF_BYCOMMAND);
        EnableMenuItem(hSystemMenu, SC_SIZE, MF_GRAYED | MF_BYCOMMAND);
        EnableMenuItem(hSystemMenu, SC_RESTORE, MF_GRAYED | MF_BYCOMMAND);
    }
}

protected override void OnSourceInitialized(EventArgs e)
{   
    base.OnSourceInitialized(e);
    RemoveUpperLeftCornerIcon();
}
© www.soinside.com 2019 - 2024. All rights reserved.