18

I'd like to know how to disable (not remove/hide) the Close button in a WPF window. I know how to hide it which makes the window's title bar look like this:

enter image description here

But I want to disable it meaning it should look like this:

enter image description here

I'm scripting in C# and using WPF (Windows Presentation Foundation).

Bubbled86
  • 461
  • 2
  • 7
  • 17
  • I found this link See if this [link][1] can Help: [1]: http://stackoverflow.com/questions/743906/how-to-hide-close-button-in-wpf-window – Vishal Jul 31 '13 at 05:54

5 Answers5

25

Try this:

public partial class MainWindow : Window
{

    [DllImport("user32.dll")]
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);


    const uint MF_BYCOMMAND = 0x00000000;
    const uint MF_GRAYED = 0x00000001;

    const uint SC_CLOSE = 0xF060;

    public MainWindow()
    {
        InitializeComponent();
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        // Disable close button
        IntPtr hwnd = new WindowInteropHelper(this).Handle;
        IntPtr hMenu = GetSystemMenu(hwnd, false);
        if (hMenu != IntPtr.Zero)
        {
            EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
        }
    }
}

Taken from here.

Make sure you set the ResizeMode to NoResize.

shelleybutterfly
  • 3,216
  • 15
  • 32
Yoav
  • 3,326
  • 3
  • 32
  • 73
  • I used this solution but I created an extension method on Window to hold the WinApi stuff, and just called .EnsureHandle() in the method instead of needing to hook OnSourceInitialized(). Note that EnsureHandle raises OnSourceInitialize(). I didn't want to pollute this answer but I will add the code in another answer. – shelleybutterfly May 26 '22 at 02:51
4

You have to override and in OnCLosing event set e.cancel=true

public MyWindow()
{
    InitializeComponent();
    this.Closing += new System.ComponentModel.CancelEventHandler(MyWindow_Closing);
}

void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    e.Cancel = true;
}
Rohit
  • 10,056
  • 7
  • 50
  • 82
  • 4
    This doesn't make button look like it's disabled. – Erti-Chris Eelmaa Jul 31 '13 at 05:50
  • Yes, but I want to actually disable the Close button instead of making it cancel the closing. – Bubbled86 Jul 31 '13 at 05:50
  • I am afraid you can only hide or override in WPF please take a look at this http://stackoverflow.com/questions/743906/how-to-hide-close-button-in-wpf-window – Rohit Jul 31 '13 at 05:52
  • 1
    @Kyle http://stackoverflow.com/a/1623991/743382 on that page seems to be *exactly* what the OP is looking for here. (Edit: I see it does a little bit more, and that little bit more is easily removed.) –  Jul 31 '13 at 05:55
  • @hvd The selected answer in the link removes the Close Icon from the window permanently and the output is something like the first image in this question which the user does not want .I hope i made it clear – Rohit Jul 31 '13 at 05:59
  • @Kyle No, it doesn't. From the comments on that answer: "The Close button itself is disable (looks gray), but not removed." –  Jul 31 '13 at 06:01
  • This doesn't make button look like disabled, but this solved my problem :) – Moses Jun 16 '22 at 00:34
2

This post which an answer using Behavior, GetWindowLong and SetWindowLong:

public class HideCloseButtonOnWindow : System.Windows.Interactivity.Behavior<Window>
{
    #region bunch of native methods

    private const int GWL_STYLE = -16;
    private const int WS_SYSMENU = 0x80000;

    [DllImport("user32.dll", SetLastError = true)]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

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

    #endregion

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += OnLoaded;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Loaded -= OnLoaded;
        base.OnDetaching();
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        var hwnd = new System.Windows.Interop.WindowInteropHelper(AssociatedObject).Handle;
        SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
    }
}

How to use it:

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:w="clr-namespace:WpfApplication2">

<i:Interaction.Behaviors>
    <w:HideCloseButtonOnWindow />
</i:Interaction.Behaviors>

</Window>
rmojab63
  • 3,513
  • 1
  • 15
  • 28
0

You can probably do it with win32 hackery.

I have done it this way: Get CustomChromeWindow(which will eventually look exactly like the one in picture), and just bind Command() property to viewmodel, and then set CanExecuteCommand=false, which will make the button disabled(How does one "disable" a button in WPF using the MVVM pattern?).

There might me this way too: How to disable close button on a window in another process with C++?

Basically, call that code with pInvoke. You can obtain WPF window handle easily.

Community
  • 1
  • 1
Erti-Chris Eelmaa
  • 25,338
  • 6
  • 61
  • 78
0

If you would like a more generic version of Yoav's accepted answer that doesn't require adding Win API calls to your Window class, here's a extension class and method:

namespace WinApi
{
    using System.Runtime.InteropServices;
    using System.Windows.Interop;

    public static class WinApi
    {
        [DllImport("user32.dll")]
        public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("user32.dll")]
        public static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);

        const uint MF_BYCOMMAND = 0x00000000;
        const uint MF_GRAYED = 0x00000001;

        const uint SC_CLOSE = 0xF060;

        public static void DisableCloseButton(this System.Windows.Window window)
        {
            // Disable close button
            IntPtr hwnd = new WindowInteropHelper(window).EnsureHandle();
            IntPtr hMenu = GetSystemMenu(hwnd, false);

            if (hMenu != IntPtr.Zero)
                EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
        }
    }
}

Then call it from your Window like so:

this.DisableCloseButton();

// or

WinApi.DisableCloseButton(this);

Since the extension uses EnsureHandle() you don't need to hook OnSourceInitialized() in your Window.

Be aware that EnsureHandle() raises OnSourceInitialized(), so don't call this until after you have done anything you want to happen prior to that call.

You can call new WindowInteropHelper(this).Handle() in your Window code if you need to check whether the handle has already been created.

shelleybutterfly
  • 3,216
  • 15
  • 32