Reputation: 436
I recently implemented the solutions from this question to hide a WPF Window's icon. I found that when that solution is used in conjunction with ResizeMode=NoResize
, the app's title bar context menu fails to disable Min/Max/Resize options.
The odd thing is the context menu doesn't incorrectly enable certain options, it just leaves the state of the context menu from before the icon was hidden. I found this using a simple test app that can make the necessary calls to hide the icon, and can update the Window's ResizeMode
on the fly.
Icon Shown, ResizeMode=CanResize
Title bar buttons and context menu are correct.
Icon Hidden, ResizeMode=CanResize
Still correct
Icon Hidden, ResizeMode=NoResize
Title bar buttons are correctly hidden, but the context menu retains it's previous state. If I switch to CanMinimize
then to NoResize
, the context menu would only have "Minimize" enabled.
This becomes a problem when a resize-able WPF Window launches another Window which is set to NoResize
(and you are hiding the icon).
Question
Are there additional Windows API functions that can force the Context Menu to reevaluate its state? What about the NoResize
option might be causing this weird behavior? As this only affects the NoResize
option, could there be a workaround at the WPF level?
EDIT - My goal is to avoid using WindowStyle=ToolWindow
or the WS_EX_TOOLWINDOW
extended window style. I've found a few problems with that window style in the past, one is desribed on this question. One of my goals with this whole approach was to emulate the look of ToolWindow
without actually having to use it.
Upvotes: 2
Views: 2187
Reputation: 1
I know it's an old question but I've also met this problem sometime ago. So if you don't want to use WS_EX_TOOLWINDOW, this can be a good solution for you. You should just gray context menu's items after hiding icon.
[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();
}
Upvotes: 0
Reputation: 5666
Using .NET 4.0 and Windows 8.1 Enterprise (I do not know if it works with other .NET versions or a different OS), you just need to use the WS_EX_TOOLWINDOW
extended style instead of the WS_EX_DLGMODALFRAME
one.
So the code will be:
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);
}
}
Let's hope it can help you.
Upvotes: 1