我最近实现了这个问题中的解决方案来隐藏 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
的外观,而无需实际使用它。
使用.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);
}
}
希望能帮到你。
我知道这是一个老问题,但我前段时间也遇到过这个问题。 因此,如果您不想使用 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();
}