94

WPF doesn't provide the ability to have a window that allows resize but doesn't have maximize or minimize buttons. I'd like to able to make such a window so I can have resizable dialog boxes.

I'm aware the solution will mean using pinvoke but I'm not sure what to call and how. A search of pinvoke.net didn't turn up any thing that jumped out at me as what I needed, mainly I'm sure because Windows Forms does provide the CanMinimize and CanMaximize properties on its windows.

Could someone point me towards or provide code (C# preferred) on how to do this?

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
Nidonocu
  • 12,476
  • 7
  • 42
  • 43

8 Answers8

126

I've stolen some code I found on the MSDN forums and made an extension method on the Window class, like this:

internal static class WindowExtensions
{
    // from winuser.h
    private const int GWL_STYLE      = -16,
                      WS_MAXIMIZEBOX = 0x10000,
                      WS_MINIMIZEBOX = 0x20000;

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

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

    internal static void HideMinimizeAndMaximizeButtons(this Window window)
    {
        IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
        var currentStyle = GetWindowLong(hwnd, GWL_STYLE);

        SetWindowLong(hwnd, GWL_STYLE, (currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX));
    }
}

The only other thing to remember is that for some reason this doesn't work from a window's constructor. I got around that by chucking this into the constructor:

this.SourceInitialized += (x, y) =>
{
    this.HideMinimizeAndMaximizeButtons();
};
starball
  • 20,030
  • 7
  • 43
  • 238
Matt Hamilton
  • 200,371
  • 61
  • 386
  • 320
  • Perhaps it would make more sense to do this after the handle has been created, perhaps in a handler for the Initialized event on the Window? – Greg D Feb 18 '10 at 21:53
  • 3
    A somewhat prettier code in the Window: protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); this.HideMinimizeAndMaximizeButtons(); } – Dmitry Shechtman Nov 02 '10 at 08:49
  • 1
    Why not make it even simpler and and subscribe to the SourceInitialized event right in the HideMinimizeAndMaximizeButtons() method? Then you can call the method from the constructor and not have to anything else. – jmatthias Feb 21 '11 at 18:58
  • The `value` variable should be of type `int` (Int32), not `long` (Int64). Then you don't need to cast it back to `int` in the next line. – Joe White Mar 08 '11 at 00:26
  • 2
    this solution does not cover double-click on title-bar. – Lonli-Lokli Sep 28 '11 at 14:09
  • 2
    @Lonli-Lokli Actually, it does. When the buttons are hidden using the Win32 API, it also disables the window context menu options and double-clicking the caption. – rookie1024 Jul 19 '16 at 23:15
  • 1
    Resurrection Note! The method has to be put into the Windows Loaded event because the handle is not defined in the Initialized event. – SezMe Mar 19 '18 at 01:23
  • 5
    After all this time knowing that this functionality is present in windows forms, I just don't understand that microsoft did not put this kind of functionality in WPF right from the start. Quite frankly, a dialog with a minimize box and a maximize book looks unprofessional, and the double clicking of the caption bar is just the same issue. Sorry ventilating my frustration over WPF a bit, it is very good and has string assets but once and a while you stumble on something that should be simple which eventually is not. – Philip Stuyck Aug 09 '18 at 10:35
  • The reason this doesn't work from the constructor is the window handle doesn't actually exist yet. Therefore, if you want to put this in the constructor without worrying about events or state or anything else, just call `EnsureHandle` on a `WindowInteropHelper` class and it will be created. Then you can use your call to hide the items. You can actually put all this code in a XAML behavior so you can set it in the XAML for the window directly, which I'd argue is where it makes the most sense. – Mark A. Donohoe Dec 02 '20 at 22:43
114

One way is to set your ResizeMode="NoResize". It will behave like this. enter image description here

starball
  • 20,030
  • 7
  • 43
  • 238
Musikero31
  • 3,115
  • 6
  • 39
  • 60
  • 40
    This would make the window not resizable, which is directly contrary to the question. – Mashmagar May 21 '12 at 17:35
  • 9
    Generally googlers that look for a way to disable minimize and maximize buttons don't have specific requirement for having window to be resizable. Currently this is top result for "wpf window disable minimize" query and this answer correctly answers the question. Regardless, shame that MS didn't made title bar or whole window chrome as "just another control or property". Too much legacy from '90... – Emperor Orionii Oct 08 '12 at 14:35
  • 2
    In this case elements with dynamic width (e.g. DockPanel) are still able to change the window size. But not the user anymore. So, this option actually met my requirements. – OneWorld Jan 11 '13 at 10:27
  • 8
    Doesn't answer the questions, but was helpful to me. Thanks. – dkantowitz Jun 12 '13 at 10:16
  • @EmperorOrionii whilst at the time this page might have been the top Google result, in no way does it imply this answer is the best when you consider it does not address _"How do I remove minimize and maximize from a `resizable window` in WPF?"_ when it **removes** the _"resizable"_ aspect from the finished product. That's like helping someone who wants to paint their car red and in the process you remove the engine. –  Nov 18 '20 at 06:14
27

Don't know if this works for your req. visually.. This is

<Window x:Class="DataBinding.MyWindow" ...Title="MyWindow" Height="300" Width="300" 
    WindowStyle="ToolWindow" ResizeMode="CanResizeWithGrip">
Community
  • 1
  • 1
Gishu
  • 134,492
  • 47
  • 225
  • 308
  • 3
    This almost works, but its still possible to maximize or minimize the window if you double click the title bar, right click and use the control menu or the taskbar button if it is avalible. Plus of course it looks like a tool window, not a normal one. – Nidonocu Dec 04 '08 at 06:02
  • Right... but then again IMHO the constraint seems odd that the user is not allowed to maximise but can manually drag-enlarge the window by resizing. But it's your window.. your rules :) – Gishu Dec 04 '08 at 06:32
  • this can be handy for situations where the `MaxWidth` and/or `MaxHeight` of the window has been set. – Brett Ryan May 16 '11 at 21:03
6

If anyone use Devexpress window (DXWindow) accepted answer doesn't work. One ugly approach is

public partial class MyAwesomeWindow : DXWindow
{
    public MyAwesomeWIndow()
    {
       Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        // hides maximize button            
        Button button = (Button)DevExpress.Xpf.Core.Native.LayoutHelper.FindElementByName(this, DXWindow.ButtonParts.PART_Maximize.ToString());
        button.IsHitTestVisible = false;
        button.Opacity = 0;

        // hides minimize button
        button = (Button)DevExpress.Xpf.Core.Native.LayoutHelper.FindElementByName(this, DXWindow.ButtonParts.PART_Minimize.ToString());
        button.IsHitTestVisible = false;
        button.Opacity = 0;

        // hides close button
        button = (Button)DevExpress.Xpf.Core.Native.LayoutHelper.FindElementByName(this, DXWindow.ButtonParts.PART_CloseButton.ToString());
        button.IsHitTestVisible = false;
        button.Opacity = 0;
    } 
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Eldar
  • 862
  • 9
  • 22
  • I probably read five different posts before I noticed your answer down here. This does work, but yuck. Did you ever find a better way? – DonBoitnott Sep 27 '17 at 19:32
3

This variant of the solution proposed by @MattHamilton can (and must) be called in the constructor of the Window. The trick is to subscribe a delegate to the SourceInitialized event within the extension method.

private const int GWL_STYLE = -16, WS_MAXIMIZEBOX = 0x10000, WS_MINIMIZEBOX = 0x20000;

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

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

/// <summary>
/// Hides the Minimize and Maximize buttons in a Window. Must be called in the constructor.
/// </summary>
/// <param name="window">The Window whose Minimize/Maximize buttons will be hidden.</param>
public static void HideMinimizeAndMaximizeButtons(this Window window)
{
    window.SourceInitialized += (s, e) => {
        IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
        int currentStyle = GetWindowLong(hwnd, GWL_STYLE);

        SetWindowLong(hwnd, GWL_STYLE, currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
    };
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
3

Here's a solution I'm using. Note that maximize button is still displayed.

Markup:

<Window x:Class="Example"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Example"
        StateChanged="Window_StateChanged">

Code behind:

// Disable maximizing this window
private void Window_StateChanged(object sender, EventArgs e)
{
    if (this.WindowState == WindowState.Maximized)
        this.WindowState = WindowState.Normal;
}
Andrej
  • 39
  • 1
2

You can set the ResizeMode="NoResize" of the window if you want to remove Minimize and Maximize button

2

Just use

WindowStyle="ToolWindow"

It hides the maximize and minimize buttons, but the window can still be resized by dragging the window borders and minimize using the hide button in the bottom right corner of the taskbar.

https://learn.microsoft.com/en-us/dotnet/api/system.windows.window.windowstyle?view=windowsdesktop-6.0