Disable maximize button of WPF window, keeping resizing feature intact

C#.NetWpf

C# Problem Overview


So WPF windows only have four resize mode options: NoResize, CanMinimize, CanResize and CanResizeWithGrip. Unfortunately, the options that enable resizing also enable maximizing the window, and those that don't are useless to me.

Is there an option to disable the maximize button while keeping the resize feature?

I'd prefer solutions that don't involve WinAPI stuff.

C# Solutions


Solution 1 - C#

Disabled only Maximize:

ResizeMode="CanMinimize"

Solution 2 - C#

WPF does not have the native capability to disable the Maximize button alone, as you can do with WinForms. You will need to resort to a WinAPI call. It's not scary:

[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

private const int GWL_STYLE = -16;
private const int WS_MAXIMIZEBOX = 0x10000;

private void Window_SourceInitialized(object sender, EventArgs e)
{
    var hwnd = new WindowInteropHelper((Window)sender).Handle;
    var value = GetWindowLong(hwnd, GWL_STYLE);
    SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MAXIMIZEBOX));
}

Solution 3 - C#

If you set

WindowStyle="ToolWindow"

In your window's properties, it will give you a resizable window with no minimize or maximize buttons at the top. It'll be square looking and the close button is also square, but at least minimize and maximize aren't there!

Solution 4 - C#

P/Invoke Method

The easiest way to call unmanaged code (C++ in this case) from managed (.NET) code is to use the Platform Invocation Services, often also referred to as P/Invoke. You simply provide the compiler with a declaration of the unmanaged function and call it like you would call any other managed method. There is an unmanaged SetWindowLong method that can be used to change an attribute of a specified window. To be able to call this method from your WPF window class using P/Invoke, you simply add the following declaration to the window class:

[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

The DllImport attribute specifies the name of the DLL that contains the method and the extern keyword tells the C# compiler that the method is implemented externally and that it won’t find any implementation or method body for it when compiling the application. The first argument to be passed to the SetWindowLong method is a handle for the window for which you want to disable any of the mentioned buttons. You can get handle for a WPF window by creating an instance of the managed WindowInteropHelper class and access its Handle property in an event handler for the window’s SourceInitialized event. This event is raised when the handle has been completely created. The second argument of the SetWindowLong method specifies the attribute or value of the window to be set, expressed as a constant integer value. When you want to change the window style, you should pass the GWL_STYLE (= -16) constant as the second argument to the method.

private const int GWL_STYLE = -16;

Finally the third argument specifies the the replacement value. There are a set of constants that you could use here:

private const int WS_MAXIMIZEBOX = 0x10000; //maximize button
private const int WS_MINIMIZEBOX = 0x20000; //minimize button

Note however that since you are supposed to pass in a DWORD that specifies the complete value for the “property” specified by the second argument, i.e. the window style in this case, you cannot simply pass any of these constants by themselves as the third argument to the method. There is another GetWindowLong method that retrieves the current value of a specific property – again the GWL_STYLE in this case – and you can then use bitwise operators to get the correct value of the third parameter to pass to the SetWindowLong method. Below is a complete code sample of how you for example could disable the minimize button for a window in WPF:

public partial class MainWindow : Window
{
 [DllImport("user32.dll")]
 private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
 [DllImport("user32.dll")]
 private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int  dwNewLong);

 private const int GWL_STYLE = -16;

 private const int WS_MAXIMIZEBOX = 0x10000; //maximize button
 private const int WS_MINIMIZEBOX = 0x20000; //minimize button

 public MainWindow() {
  InitializeComponent();
  this.SourceInitialized += MainWindow_SourceInitialized;
}

private IntPtr _windowHandle;
private void MainWindow_SourceInitialized(object sender, EventArgs e) {
_windowHandle = new WindowInteropHelper(this).Handle;

 //disable minimize button
 DisableMinimizeButton();
}

protected void DisableMinimizeButton() {
  if (_windowHandle == IntPtr.Zero)
    throw new InvalidOperationException("The window has not yet been completely initialized");

   SetWindowLong(_windowHandle, GWL_STYLE, GetWindowLong(_windowHandle,  GWL_STYLE) & ~WS_MAXIMIZEBOX);
 }
}

Disabling the minimize button is then simply a matter of replacing the WS_MAXIMIZEBOX constant with the WS_MINIMIZEBOX

Solution 5 - C#

Another option is catching the StateChanged event which is raised when the window is maximized. Then simply set the WindowState to "Normal".

This however does not hide the maximize box!

private void Window_StateChanged(object sender, EventArgs e)
{
	if (WindowState == WindowState.Maximized)
	{
		WindowState = WindowState.Normal;
	}
}

Solution 6 - C#

You can create a custom window by setting WindowStyle to None, which removes the Minimize, Maximize and Close buttons, and create yourself the buttons you need. That's a great example for this:

http://www.codeproject.com/Articles/131515/WPF-Custom-Chrome-Library

It gives you some extra work, but if you realy don't want to use WinAPI, that's an option.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter W.View Question on Stackoverflow
Solution 1 - C#5573352View Answer on Stackoverflow
Solution 2 - C#ScottView Answer on Stackoverflow
Solution 3 - C#TranquilMarmotView Answer on Stackoverflow
Solution 4 - C#Shahid NeermundaView Answer on Stackoverflow
Solution 5 - C#bytecode77View Answer on Stackoverflow
Solution 6 - C#ProgrammerView Answer on Stackoverflow