Question

How to disable maximizing WPF window on double click on the caption and leave resizing available?


I know that ResizeMode disables maximizing, but it also prevents resizing the form

ResizeMode="CanMinimize"

I know how to remove maximize and minimize buttons, but it's still possible to maximize by double click on the caption.

In WinForms it can be achieved easily. Just set FormBorderStyle from None to FixedSingle or Fixed3D. But it's not an option in WPF any more.


P.S. I'm trying some tricks with handling WM_GETMINMAXINFO, WM_SYSCOMMAND, etc. But seems it's not working...

Was it helpful?

Solution 3

WPF does not have a native way to disable maximizing windows (unlike WinForms). Hence consider the following key points:

1. Hide the Maximize button

Using WinAPI is a way to go, but only for hiding the Maximize button. Use the following:

[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));
}

2. Handling maximizing manually

That code above still allows maximizing (e.g. by double click on the window's title).

WPF has no control on the title bar behavior. if you want to change the double click behavior you will need to remove the title bar and create you own. Take a look how it's been done in MahApps.Metro - link to sample. After that handle double click event.

OTHER TIPS

Good solution I put together with a little help from MSDN on detecting non-client mouse activity in WPF windows.

Calling handled = true in the WndProc if msg == WM_NCLBUTTONDBLCLK will prevent the window from maximizing when the user double clicks on the non-client area.

myClass()  //c'tor
{
  InitializeComponent();
  SourceInitialized += new EventHandler(myClass_SourceInitialized);  
}

void myClass_SourceInitialized(object sender, EventArgs e)
{
    System.Windows.Interop.HwndSource source = System.Windows.Interop.HwndSource.FromHwnd(new System.Windows.Interop.WindowInteropHelper(this).Handle);
    source.AddHook(new System.Windows.Interop.HwndSourceHook(WndProc));
}

int WM_NCLBUTTONDBLCLK { get { return 0x00A3; } }

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_NCLBUTTONDBLCLK)
    {
        handled = true;  //prevent double click from maximizing the window.
    }

    return IntPtr.Zero;
}

Helpful MSDN ref: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f54dde25-b748-4724-a7fe-a355b086cfd4/mouse-event-in-the-nonclient-window-area

I had a similar issue. My window does not have any form border or title bar, but it can be moved around (using the mouse). The problem is that if a user moves the window to the top edge of the screen, then Windows automatically maximizes the window.

I managed to work around this issue by attaching the following handler to the window's StateChanged event.

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

After encountering this problem and researching this SO question I decided that the answers were not sufficient. After removing the Title Bar the window still maximizes when double clicking close to the top of the window.

I chose the approach of removing the title bar and disabling double clicking on the window.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        MouseDoubleClick += (sender, args) =>
        {
            args.Handled = true;
        };
    }
}

In my application I was using MahApps.Metro which would inherit from MetroWindow instead of Window however the above example should work in both cases.

Does this work for you?

public partial class MainWindow : Window
 {
    public MainWindow()
   {

    InitializeComponent();
    this.SizeChanged += MainWindow_SizeChanged;
   }    
    void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
    {

      if (this.WindowState == WindowState.Maximized)
      {
       this.WindowState = System.Windows.WindowState.Normal;
      }


}
}

Another simple (but ugly) solution:

// inside a Window class
protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
{
    base.OnPreviewMouseDoubleClick(e);

    const int titleHeight = 30;
    var position = e.GetPosition(this);

    if (position.Y <= titleHeight)
    {
        e.Handled = true;
    }
}

Note: The user can still maximizing the window using the contextmenu on the title bar / moving the window to the upper edge of the screen.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top