233

I'm writing a modal dialog in WPF. How do I set a WPF window to not have a close button? I'd still like for its WindowState to have a normal title bar.

I found ResizeMode, WindowState, and WindowStyle, but none of those properties allow me to hide the close button but show the title bar, as in modal dialogs.

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Michael Hedgpeth
  • 7,732
  • 10
  • 47
  • 66
  • 9
    It's a progress dialog running a background thread that doesn't support cancelling; I guess I'm just trying to make it so I don't have to support cancelling (yet). You're probably right, though. – Michael Hedgpeth Apr 13 '09 at 14:18
  • 1
    I also hate apps trying to remove window chrome. If I make a progress dialog, I always make the window Close button do the same logic as clicking the actual Cancel button. – Christian Hayter Jul 09 '10 at 10:09
  • 13
    For Chris: Lets imagine your software is for Video Surveillance. A security Agent during the night HAS (that's his job) to keep the windows opened... but sometimes their work is boring and they want to surf Internet or close the Video Matrices windows for any reason, removing the windows buttons is the proper way to do it. – Jean-Marie Jun 30 '12 at 20:26
  • Does your modal dialog have a cancel button? If so, could you treat hitting the close button the same as pressing Cancel? – Andy Apr 13 '09 at 14:13
  • It's a progress dialog for a background worker. I'm starting to think that not including a window title would probably be best. – Michael Hedgpeth Apr 13 '09 at 14:16
  • 7
    @ChrisUpchurch, _"Why do you want to do this? It strikes me as really lousy UI design. "_ - really "lousy UI design" is when a program presents a dialog box with **OK**; **Cancel** and **Close** buttons. To a user, it may not be obvious what **Close** does. Does it _cancel_ or _submit_? [Consensus is not to include close buttons in dialogs](http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/1118766571/ref=asap_B001IGLP7M_1_1?s=books&ie=UTF8&qid=1414982440&sr=1-1) so there is that –  Nov 03 '14 at 06:20
  • 2
    @Jean-Marie But hiding the close button doesn't prevent that from happening, it only fools the uninformed and lazy(to Google). Hiding the close button only prevents clicking that button. Win key and alt key combos will still work as normal The "proper" way to do it, is to make a user account for workers, with a group policy that prevents them from opening/installing any software other than what's approved.Then have an admin account, that supervisors have access to, to handle any maintenance. – Digital_Utopia Nov 20 '15 at 03:50

24 Answers24

296

WPF doesn't have a built-in property to hide the title bar's Close button, but you can do it with a few lines of P/Invoke.

First, add these declarations to your Window class:

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

Then put this code in the Window's Loaded event:

var hwnd = new WindowInteropHelper(this).Handle;
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);

And there you go: no more Close button. You also won't have a window icon on the left side of the title bar, which means no system menu, even when you right-click the title bar - they all go together.

Important note: all this does is hide the button. The user can still close the window! If the user presses Alt+F4, or closes the app via the taskbar, the window will still close.

If you don't want to allow the window to close before the background thread is done, then you could also override OnClosing and set Cancel to true, as Gabe suggested.

Joe White
  • 94,807
  • 60
  • 220
  • 330
  • 5
    According to the docs we should be using `SetWindowLongPtr` instead. – Jonathan Allen Jul 26 '10 at 21:42
  • 15
    Mostly a note to self... Namespace of DllImport -> System.Runtime.InteropServices.DllImport. Namespace of WindowInteropHelper -> System.Windows.Interop.WindowInteropHelper – doobop Oct 28 '10 at 15:21
  • 4
    Actually, this approach hides all three buttons (Min, Max and Close). Is it possible to just hide the Close button? – newman May 14 '13 at 14:58
  • 4
    @miliu, nope. You can [disable it](http://stackoverflow.com/a/1623991/87399), but you can't hide it without hiding Minimize/Maximize as well. I suspect the Windows devs thought it would be confusing if Maximize was on the right where Close usually is. – Joe White May 15 '13 at 02:49
  • 6
    Put WindowStyle="None" on your Window tag in the XAML file. – diegodsp Aug 12 '15 at 18:21
  • 2
    @diegodsp, from the original question: "I'd still like for its WindowState to have a normal title bar." WindowStyle=None has *no* title bar. – Joe White Aug 13 '15 at 01:08
  • 2
    More difficulty from WPF for even the most trivial tasks. Gawd I am not liking learning WPF. – Jonathan Wood Jun 24 '16 at 00:26
  • 1
    Forgot to mention you need a `this.Loaded += new RoutedEventHandler(Window_Loaded)` line in the code that runs onload, so it will pick up the event, and `Window_Loaded` needs to be instatiated as `private void Window_Loaded(object sender, RoutedEventArgs e) { ... }`. Not everyone knows these things. – vapcguy Mar 21 '17 at 17:59
  • Please note that setting WindowStyle="None", whilst it hides all the buttons prevents the window from being moved. This option still allows that. – Daniel Hollinrake Jul 08 '19 at 11:38
  • i can still close it from task bar – Mike Yang Feb 03 '21 at 03:15
  • 1
    @MikeYang Good point. This is just another case of the user still being able to close the window with Alt+F4, but it's probably more likely for people to run into the taskbar-close scenario. I expanded my answer a bit to further call out the fact that hiding the button doesn't actually prevent closing the window. – Joe White Feb 03 '21 at 22:14
102

I just got to similar problem and Joe White's solution seems to me simple and clean. I reused it and defined it as an attached property of Window

public class WindowBehavior
{
    private static readonly Type OwnerType = typeof (WindowBehavior);

    #region HideCloseButton (attached property)

    public static readonly DependencyProperty HideCloseButtonProperty =
        DependencyProperty.RegisterAttached(
            "HideCloseButton",
            typeof (bool),
            OwnerType,
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(HideCloseButtonChangedCallback)));

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static bool GetHideCloseButton(Window obj) {
        return (bool)obj.GetValue(HideCloseButtonProperty);
    }

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static void SetHideCloseButton(Window obj, bool value) {
        obj.SetValue(HideCloseButtonProperty, value);
    }

    private static void HideCloseButtonChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window == null) return;

        var hideCloseButton = (bool)e.NewValue;
        if (hideCloseButton && !GetIsHiddenCloseButton(window)) {
            if (!window.IsLoaded) {
                window.Loaded += HideWhenLoadedDelegate;
            }
            else {
                HideCloseButton(window);
            }
            SetIsHiddenCloseButton(window, true);
        }
        else if (!hideCloseButton && GetIsHiddenCloseButton(window)) {
            if (!window.IsLoaded) {
                window.Loaded -= ShowWhenLoadedDelegate;
            }
            else {
                ShowCloseButton(window);
            }
            SetIsHiddenCloseButton(window, false);
        }
    }

    #region Win32 imports

    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

    private static readonly RoutedEventHandler HideWhenLoadedDelegate = (sender, args) => {
        if (sender is Window == false) return;
        var w = (Window)sender;
        HideCloseButton(w);
        w.Loaded -= HideWhenLoadedDelegate;
    };

    private static readonly RoutedEventHandler ShowWhenLoadedDelegate = (sender, args) => {
        if (sender is Window == false) return;
        var w = (Window)sender;
        ShowCloseButton(w);
        w.Loaded -= ShowWhenLoadedDelegate;
    };

    private static void HideCloseButton(Window w) {
        var hwnd = new WindowInteropHelper(w).Handle;
        SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
    }

    private static void ShowCloseButton(Window w) {
        var hwnd = new WindowInteropHelper(w).Handle;
        SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU);
    }

    #endregion

    #region IsHiddenCloseButton (readonly attached property)

    private static readonly DependencyPropertyKey IsHiddenCloseButtonKey =
        DependencyProperty.RegisterAttachedReadOnly(
            "IsHiddenCloseButton",
            typeof (bool),
            OwnerType,
            new FrameworkPropertyMetadata(false));

    public static readonly DependencyProperty IsHiddenCloseButtonProperty =
        IsHiddenCloseButtonKey.DependencyProperty;

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static bool GetIsHiddenCloseButton(Window obj) {
        return (bool)obj.GetValue(IsHiddenCloseButtonProperty);
    }

    private static void SetIsHiddenCloseButton(Window obj, bool value) {
        obj.SetValue(IsHiddenCloseButtonKey, value);
    }

    #endregion

}

Then in XAML you just set it like this:

<Window 
    x:Class="WafClient.Presentation.Views.SampleWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:u="clr-namespace:WafClient.Presentation.Behaviors"
    ResizeMode="NoResize"
    u:WindowBehavior.HideCloseButton="True">
    ...
</Window>
StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
SpudCZ
  • 1,039
  • 1
  • 7
  • 5
  • 2
    Should it be `window.Loaded += ShowWhenLoadedDelegate;` instead of `-=` ? Otherwise I don't see anywhere that ShowWhenLoadedDelegate could ever be called. – StayOnTarget Aug 14 '20 at 19:56
76

Set WindowStyle property to None which will hide the control box along with the title bar. No need to kernal calls.

Sriwantha Attanayake
  • 7,694
  • 5
  • 42
  • 44
  • Not sure why all the other answers. var win = new Window(); win.WindowStyle = WindowStyle.None; win.Show(); – Talon Mar 20 '13 at 11:37
  • In my opinion, this is by far the best answer of them all, I am new to WPF and was just looking into this matter, brilliant! – Antonio Teh Sumtin Mar 26 '13 at 18:53
  • 23
    Well, this will hide the window title bar completely. That means you don't get window title and user will not be able to move the window. – newman May 14 '13 at 15:00
  • 11
    You can make the window movable by adding `this.DragMove();` to the window's `MouseDown` event – paul Feb 20 '14 at 21:55
  • 2
    For a modal dialog that should be purely informational and mandatory, like progress on upgrading a database with an old schema that has been opened, this solution is perfect. – The Lonely Coder Dec 03 '14 at 12:08
  • 1
    I think some people would like to have a border, though – pjdupreez Jan 08 '15 at 14:15
  • Fully agree with @pjdupreez - a dialog box without the title bar is both ugly and non-descriptive. Voting down because it's a shotgun approach. Most I feel would not want to do it this way if it could be avoided - especially when an alternative DOES exist. – vapcguy Mar 21 '17 at 18:04
  • 2
    Definitely the best solution. There is no problem with adding border to panel, or implementing moving. – buks Jul 20 '17 at 13:49
  • Don't vote down a solution just because you prefer a different solution. Different variations of problem benefit from a variety of solutions. We should encourage that diversity in thinking. – Jeff Oct 17 '22 at 18:00
58

This won't get rid of the close button, but it will stop someone closing the window.

Put this in your code behind file:

protected override void OnClosing(CancelEventArgs e)
{
   base.OnClosing(e);
   e.Cancel = true;
}
Ian Gregory
  • 5,770
  • 1
  • 29
  • 42
flurbius
  • 957
  • 7
  • 14
  • 8
    Be aware that doing this in a `Window` that is set up as a modal dialog will interfere with the `Window` setting its `DialogResult` property and may make it unusable. http://stackoverflow.com/questions/898708/cant-set-dialogresult-in-wpf – Sheridan Aug 13 '12 at 10:28
  • 4
    I was getting an overflow using this method, I took out base.OnClosing(e) and then it worked – jacobsgriffith Jun 20 '14 at 16:41
  • 11
    As a user i would hate the programmer who put this into their application –  May 20 '15 at 08:58
  • 2
    @UrbanEsc I would tend to agree that its an annoying thing to do, but when I did this - and it was only the one time - it was a mandatory requirement, and it was a necessary evil, there was some very important process going on that could not be interrupted and the app couldn't proceed until it was done. There were other ways it could have been done (a background thread, with the UI disabled until ready) but the boss and client both liked it this way because it emphasised the gravity of the process. – flurbius Jul 29 '17 at 20:51
  • This is good after setting `WindowStyle=None`, so that the user won't close the window from the taskbar. – Hossein Ebrahimi Jul 09 '23 at 11:14
18

To disable close button you should add the following code to your Window class (the code was taken from here, edited and reformatted a bit):

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

    HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;

    if (hwndSource != null)
    {
        hwndSource.AddHook(HwndSourceHook);
    }

}

private bool allowClosing = false;

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

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

private const uint SC_CLOSE = 0xF060;

private const int WM_SHOWWINDOW = 0x00000018;
private const int WM_CLOSE = 0x10;

private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case WM_SHOWWINDOW:
            {
                IntPtr hMenu = GetSystemMenu(hwnd, false);
                if (hMenu != IntPtr.Zero)
                {
                    EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
                }
            }
            break;
        case WM_CLOSE:
            if (!allowClosing)
            {
                handled = true;
            }
            break;
    }
    return IntPtr.Zero;
}

This code also disables close item in System menu and disallows closing the dialog using Alt+F4.

You will probably want to close the window programmatically. Just calling Close() will not work. Do something like this:

allowClosing = true;
Close();
Viachaslau Tysianchuk
  • 1,680
  • 19
  • 22
  • In Windows 7: The above also disables (but does not remove) the Close item in the drop-down System menu. The Close button itself is disable (looks gray), but not removed. This trick does not work for the Minimize/Maximize item/button -- I suspect WPF re-enables them. –  Apr 10 '10 at 20:46
  • 4
    Disabling the button is better than just removing them, it keeps a consistent feel while letting the user know that an important operation is running. – Robert Baker May 08 '11 at 23:47
10

I was trying Viachaslau's answer since I like the idea of not removing the button but disabling it, but for some reason it did not always work: the close button was still enabled but no errors whatsoever.

This on the other hand always worked (error checking omitted):

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

private const uint MF_BYCOMMAND = 0x00000000;
private const uint MF_GRAYED = 0x00000001;
private const uint SC_CLOSE = 0xF060;
private const int WM_SHOWWINDOW = 0x00000018;

protected override void OnSourceInitialized( EventArgs e )
{
  base.OnSourceInitialized( e );
  var hWnd = new WindowInteropHelper( this );
  var sysMenu = GetSystemMenu( hWnd.Handle, false );
  EnableMenuItem( sysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED );
}
stijn
  • 34,664
  • 13
  • 111
  • 163
10

The property to set is => WindowStyle="None"

<Window x:Class="mdaframework.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Start" Height="350" Width="525" ResizeMode="NoResize"  WindowStartupLocation="CenterScreen" WindowStyle="None">
Rahil Wazir
  • 10,007
  • 11
  • 42
  • 64
daniele3004
  • 13,072
  • 12
  • 67
  • 75
10

I just add my implementation of Joe White's answer using Interactivity Behavior (you need to reference System.Windows.Interactivity).

code:

public class HideCloseButtonOnWindow : 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 WindowInteropHelper(AssociatedObject).Handle;
        SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
    }
}

usage:

<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>
Community
  • 1
  • 1
tom.maruska
  • 1,411
  • 16
  • 22
  • If you are not able to reference System.Windows.Interactivity, check this link: https://stackoverflow.com/questions/8360209/how-to-add-system-windows-interactivity-to-project – Ivan P. Mar 20 '23 at 12:19
  • Also, the reference to namespace (in 'usage') should be: `xmlns:i="http://schemas.microsoft.com/xaml/behaviors"` . It worked – Ivan P. Mar 20 '23 at 12:29
  • Addition to my previous comment: I installed `Microsoft.Xaml.Behaviors.Wpf` Nuget package – Ivan P. Mar 20 '23 at 12:31
2

The following is about disabling the close and Maximize/Minimize buttons, it does not actually remove the buttons (but it does remove the menu items!). The buttons on the title bar are drawn in a disabled/grayed state. (I'm not quite ready to take over all the functionality myself ^^)

This is slightly different than Virgoss solution in that it removes the menu items (and the trailing separator, if needed) instead of just disabling them. It differs from Joe Whites solution as it does not disable the entire system menu and so, in my case, I can keep around the Minimize button and icon.

The follow code also supports disabling the Maximize/Minimize buttons as, unlike the Close button, removing the entries from the menu does not cause the system to render the buttons "disabled" even though removing the menu entries does disable the functionality of the buttons.

It works for me. YMMV.

    using System;
    using System.Collections.Generic;
    using System.Text;

    using System.Runtime.InteropServices;
    using Window = System.Windows.Window;
    using WindowInteropHelper = System.Windows.Interop.WindowInteropHelper;
    using Win32Exception = System.ComponentModel.Win32Exception;

    namespace Channelmatter.Guppy
    {

        public class WindowUtil
        {
            const int MF_BYCOMMAND = 0x0000;
            const int MF_BYPOSITION = 0x0400;

            const uint MFT_SEPARATOR = 0x0800;

            const uint MIIM_FTYPE = 0x0100;

            [DllImport("user32", SetLastError=true)]
            private static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);

            [DllImport("user32", SetLastError=true)]
            private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

            [DllImport("user32", SetLastError=true)]
            private static extern int GetMenuItemCount(IntPtr hWnd);

            [StructLayout(LayoutKind.Sequential)]
            public struct MenuItemInfo {
                public uint   cbSize;
                public uint   fMask;
                public uint   fType;
                public uint   fState;
                public uint   wID;
                public IntPtr hSubMenu;
                public IntPtr hbmpChecked;
                public IntPtr hbmpUnchecked;
                public IntPtr dwItemData; // ULONG_PTR
                public IntPtr dwTypeData;
                public uint   cch;
                public IntPtr hbmpItem;
            };

            [DllImport("user32", SetLastError=true)]
            private static extern int GetMenuItemInfo(
                IntPtr hMenu, uint uItem,
                bool fByPosition, ref MenuItemInfo itemInfo);

            public enum MenuCommand : uint
            {
                SC_CLOSE = 0xF060,
                SC_MAXIMIZE = 0xF030,
            }

            public static void WithSystemMenu (Window win, Action<IntPtr> action) {
                var interop = new WindowInteropHelper(win);
                IntPtr hMenu = GetSystemMenu(interop.Handle, false);
                if (hMenu == IntPtr.Zero) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to get system menu");
                } else {
                    action(hMenu);
                }
            }

            // Removes the menu item for the specific command.
            // This will disable and gray the Close button and disable the
            // functionality behind the Maximize/Minimuze buttons, but it won't
            // gray out the Maximize/Minimize buttons. It will also not stop
            // the default Alt+F4 behavior.
            public static void RemoveMenuItem (Window win, MenuCommand command) {
                WithSystemMenu(win, (hMenu) => {
                    if (RemoveMenu(hMenu, (uint)command, MF_BYCOMMAND) == 0) {
                        throw new Win32Exception(Marshal.GetLastWin32Error(),
                            "Failed to remove menu item");
                    }
                });
            }

            public static bool RemoveTrailingSeparator (Window win) {
                bool result = false; // Func<...> not in .NET3 :-/
                WithSystemMenu(win, (hMenu) => {
                    result = RemoveTrailingSeparator(hMenu);
                });
                return result;
            }

            // Removes the final trailing separator of a menu if it exists.
            // Returns true if a separator is removed.
            public static bool RemoveTrailingSeparator (IntPtr hMenu) {
                int menuItemCount = GetMenuItemCount(hMenu);
                if (menuItemCount < 0) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to get menu item count");
                }
                if (menuItemCount == 0) {
                    return false;
                } else {
                    uint index = (uint)(menuItemCount - 1);
                    MenuItemInfo itemInfo = new MenuItemInfo {
                        cbSize = (uint)Marshal.SizeOf(typeof(MenuItemInfo)),
                        fMask = MIIM_FTYPE,
                    };

                    if (GetMenuItemInfo(hMenu, index, true, ref itemInfo) == 0) {
                        throw new Win32Exception(Marshal.GetLastWin32Error(),
                            "Failed to get menu item info");
                    }

                    if (itemInfo.fType == MFT_SEPARATOR) {
                        if (RemoveMenu(hMenu, index, MF_BYPOSITION) == 0) {
                            throw new Win32Exception(Marshal.GetLastWin32Error(),
                                "Failed to remove menu item");
                        }
                        return true;
                    } else {
                        return false;
                    }
                }
            }

            private const int GWL_STYLE = -16;

            [Flags]
            public enum WindowStyle : int
            {
                WS_MINIMIZEBOX = 0x00020000,
                WS_MAXIMIZEBOX = 0x00010000,
            }

            // Don't use this version for dealing with pointers
            [DllImport("user32", SetLastError=true)]
            private static extern int SetWindowLong (IntPtr hWnd, int nIndex, int dwNewLong);

            // Don't use this version for dealing with pointers
            [DllImport("user32", SetLastError=true)]
            private static extern int GetWindowLong (IntPtr hWnd, int nIndex);

            public static int AlterWindowStyle (Window win,
                WindowStyle orFlags, WindowStyle andNotFlags) 
            {
                var interop = new WindowInteropHelper(win);

                int prevStyle = GetWindowLong(interop.Handle, GWL_STYLE);
                if (prevStyle == 0) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to get window style");
                }

                int newStyle = (prevStyle | (int)orFlags) & ~((int)andNotFlags);
                if (SetWindowLong(interop.Handle, GWL_STYLE, newStyle) == 0) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to set window style");
                }
                return prevStyle;
            }

            public static int DisableMaximizeButton (Window win) {
                return AlterWindowStyle(win, 0, WindowStyle.WS_MAXIMIZEBOX);
            }
        }
    }

Usage: This must be done AFTER the source is initialized. A good place is to use the SourceInitialized event of the Window:

Window win = ...; /* the Window :-) */
WindowUtil.DisableMaximizeButton(win);
WindowUtil.RemoveMenuItem(win, WindowUtil.MenuCommand.SC_MAXIMIZE);
WindowUtil.RemoveMenuItem(win, WindowUtil.MenuCommand.SC_CLOSE);
while (WindowUtil.RemoveTrailingSeparator(win)) 
{
   //do it here
}

To disable the Alt+F4 functionality the easy method is just to wire up the Canceling event and use set a flag for when you really do want to close the window.

daniele3004
  • 13,072
  • 12
  • 67
  • 75
2

Let the user "close" the window but really just hide it.

In the window's OnClosing event, hide the window if already visible:

    If Me.Visibility = Windows.Visibility.Visible Then
        Me.Visibility = Windows.Visibility.Hidden
        e.Cancel = True
    End If

Each time the Background thread is to be executed, re-show background UI window:

    w.Visibility = Windows.Visibility.Visible
    w.Show()

When terminating execution of program, make sure all windows are/can-be closed:

Private Sub CloseAll()
    If w IsNot Nothing Then
        w.Visibility = Windows.Visibility.Collapsed ' Tell OnClosing to really close
        w.Close()
    End If
End Sub
BSalita
  • 8,420
  • 10
  • 51
  • 68
2

Here is how I achieved the similar goal using custom styles without DllImports and P/Invoke calls. This removes the existing title bar using WindowStyle="none" and shows a 'TextBlock' with similar background color to indicate as title bar.

enter image description here

XAML Code

<Window x:Class="AddBook"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="http://wpftoolkit.my-libraries.com/v5" 
    WindowStartupLocation="CenterOwner"        
    ResizeMode="NoResize" 
    Style="{DynamicResource WindowStyleX}"
    ShowInTaskbar="False"
    ShowActivated="True"
    SizeToContent="Height"
    Title="Add New Book" 
    Width="450">
..............

</Window>

XAML

<Style x:Key="WindowStyleX" TargetType="{x:Type Window}">
<Setter Property="WindowStyle" Value="None" />
<Setter Property="AllowsTransparency" Value="False" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Window}">
            <Border BorderBrush="{DynamicResource BlackColor}" BorderThickness="1">
                <Grid Background="{TemplateBinding Background}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Border
                        Grid.Row="0"
                        Grid.ColumnSpan="2"
                        Background="{DynamicResource BlackColor}">
                        <Grid>
                            <TextBlock
                                Grid.Column="1"
                                Margin="10,0,0,0"
                                HorizontalAlignment="Left"
                                VerticalAlignment="Center"
                                FontSize="16"
                                Foreground="{DynamicResource WhiteTextForeground}"
                                Text="{TemplateBinding Title}" />
                        </Grid>
                    </Border>
                    <ContentPresenter Grid.Row="1" />
                </Grid>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>
Saqib
  • 1,283
  • 1
  • 13
  • 16
1

As stated in other answers, you can use WindowStyle="None" to remove the Title Bar altogether.

And, as stated in the comments to those other answers, this prevents the window from being draggable so it is hard to move it from its initial position.

However, you can overcome this by adding a single line of code to the Constructor in the Window's Code Behind file:

MouseDown += delegate { DragMove(); };

Or, if you prefer Lambda Syntax:

MouseDown += (sender, args) => DragMove();

This makes the entire Window draggable. Any interactive controls present in the Window, such as Buttons, will still work as normal and won't act as drag-handles for the Window.

Holf
  • 5,605
  • 3
  • 42
  • 63
  • Still a bad idea. It removes the whole title bar, making this a shotgun approach, and makes the box look ugly and means there's no title/description for it. There are much better alternatives. – vapcguy Mar 21 '17 at 18:15
  • @vapcguy It removes the whole title bar. It is a shotgun approach. Makes the box look ugly? Your opinion. Much better alternatives? For you, perhaps. Not for everybody. :-) – Holf Aug 02 '17 at 10:40
1

This doesn't hide the button but will prevent the user from moving forward by shutting down the window.

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{            
    if (e.Cancel == false)
    {
        Application.Current.Shutdown();
    }
}
A. Lartey
  • 59
  • 2
1

So, pretty much here is your problem. The close button on the upper right of a window frame is not part of the WPF window, but it belongs to the part of the window frame that is controled by your OS. This means you will have to use Win32 interop to do it.

alternativly, you can use the noframe and either provide your own "frame" or have no frame at all.

Muad'Dib
  • 28,542
  • 5
  • 55
  • 68
0

Try adding a Closing event to the window. Add this code to the event handler.

e.Cancel = true;

This will prevent the window from closing. This has the same effect as hiding the close button.

Dennis R
  • 69
  • 1
  • 1
  • 9
  • 2
    "This has the same effect as hiding the close button." except that the button is still visible and clickable, i.e. it's animated and depresses visually when you click it -- which defies [POLA](https://en.wikipedia.org/wiki/Principle_of_least_astonishment). – rory.ap Dec 20 '16 at 12:21
0

Use this, modified from https://stephenhaunts.com/2014/09/25/remove-the-close-button-from-a-wpf-window :

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;

namespace Whatever
{
    public partial class MainMenu : Window
    {
        private const int GWL_STYLE = -16;
        private const int WS_SYSMENU = 0x00080000;

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

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

        public MainMenu()
        {
             InitializeComponent();
             this.Loaded += new RoutedEventHandler(Window_Loaded);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var hwnd = new WindowInteropHelper(this).Handle;
            SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_SYSMENU);
        }  

    }
}
vapcguy
  • 7,097
  • 1
  • 56
  • 52
0

I very much like this answer which uses attached properties to mediate the behavior. However, I found that answer's implementation overly complicated, and it also doesn't address the secondary goal of preventing the window from being closed even with Alt+F4. So I offer this alternative:

enum CloseButtonVisibility
{
    Visible,
    Hidden,
    CloseDisabled,
}

static class WindowEx
{
    private static readonly CancelEventHandler _cancelCloseHandler = (sender, e) => e.Cancel = true;

    public static readonly DependencyProperty CloseButtonVisibilityProperty =
        DependencyProperty.RegisterAttached(
            "CloseButtonVisibility",
            typeof(CloseButtonVisibility),
            typeof(WindowEx),
            new FrameworkPropertyMetadata(CloseButtonVisibility.Visible, new PropertyChangedCallback(_OnCloseButtonChanged)));

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static CloseButtonVisibility GetCloseButtonVisibility(Window obj)
    {
        return (CloseButtonVisibility)obj.GetValue(CloseButtonVisibilityProperty);
    }

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static void SetCloseButtonVisibility(Window obj, CloseButtonVisibility value)
    {
        obj.SetValue(CloseButtonVisibilityProperty, value);
    }

    private static void _OnCloseButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is Window window))
        {
            return;
        }

        if (e.OldValue is CloseButtonVisibility oldVisibility)
        {
            if (oldVisibility == CloseButtonVisibility.CloseDisabled)
            {
                window.Closing -= _cancelCloseHandler;
            }
        }

        if (e.NewValue is CloseButtonVisibility newVisibility)
        {
            if (newVisibility == CloseButtonVisibility.CloseDisabled)
            {
                window.Closing += _cancelCloseHandler;
            }

            if (!window.IsLoaded)
            {
                // NOTE: if the property is set multiple times before the window is loaded,
                // the window will wind up with multiple event handlers. But they will all
                // set the same value, so this is fine from a functionality point of view.
                //
                // The handler is never unsubscribed, so there is some nominal overhead there.
                // But it would be incredibly unusual for this to be set more than once
                // before the window is loaded, and even a handful of delegate instances
                // being around that are no longer needed is not really a big deal.
                window.Loaded += _ApplyCloseButtonVisibility;
            }
            else
            {
                _SetVisibility(window, newVisibility);
            }
        }
    }

    #region Win32 imports

    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

    private static void _ApplyCloseButtonVisibility(object sender, RoutedEventArgs e)
    {
        Window window = (Window)sender;
        CloseButtonVisibility visibility = GetCloseButtonVisibility(window);

        _SetVisibility(window, visibility);
    }

    private static void _SetVisibility(Window window, CloseButtonVisibility visibility)
    {
        var hwnd = new WindowInteropHelper(window).Handle;

        if (visibility == CloseButtonVisibility.Visible)
        {
            SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU);
        }
        else
        {
            SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
        }
    }
}

This provides three states to choose from:

  1. Visible
  2. Hidden, but user can still close using Alt+F4
  3. Hidden, and closing is disabled completely

Note that by default, a window that is never closed will prevent a WPF program's process from terminating. So if you choose to use the CloseButtonVisibility.CloseDisabled value, you will need to either customize the Application.Run() behavior, or re-enable closing of the window before exiting. E.g. in your main window, you might have something like this:

protected override void OnClosed(EventArgs e)
{
    WindowEx.SetCloseButtonVisibility(this.toolWindow.Value, CloseButtonVisibility.Hidden);
    this.toolWindow.Value.Close();

    base.OnClosed(e);
}

where toolWindow is the Window reference for the window with the close button disabled.

The above assumes that the window is normally just hidden and shown as needed during the normal UI activity. Of course, you can also choose to close the window explicitly at any time, but the same technique — setting the option to not disable closing, and then explicitly closing the window — would still apply.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
0

You may run into the need to toggle the window state depending on what page or user control is currently being displayed. (Yes, this is an unusual scenario, but it can happen. In our case we have a user control in our application that is displayed on an external touch screen for customers to interact with. We don't want our customers to have touch access to close the screen. But the rest of the application uses standard windows frames.) To do this from the code behind of the page or user control. Note: You must run it from the Loaded event not the constructor because the control hasn't been populated in the constructor and it will throw an exception.

// To toggle it off
Window.GetWindow(this).WindowStyle = WindowStyle.None;

// To turn it back on toggle it off
Window.GetWindow(this).WindowStyle = WindowStyle.SingleBorderWindow;
Jeff
  • 8,020
  • 34
  • 99
  • 157
0

XAML Code

<Button Command="Open" Content="_Open">
    <Button.Style>
        <Style TargetType="Button">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Visibility" Value="Collapsed" />
                </Trigger>
            </Style.Triggers>
        </Style>
     </Button.Style>
</Button>

should work

Edit- for your instant this Thread shows how that can be done but I don't think Window has a property to get what you want without losing the normal title bar.

Edit 2 This Thread shows a way for it to be done, but you must apply your own style to the system menu and it shows a way how you can do that.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
TStamper
  • 30,098
  • 10
  • 66
  • 73
0

To add to the menagerie of answers, here's a few options which permit binding whether the close button is disabled.

Custom window (add reference to nuget Esatto.Win32.CustomControls / or source):

<win32:NonClosableWindow x:Class="BindableCloseButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:win32="clr-namespace:Esatto.Win32.Wpf;assembly=Esatto.Win32.CommonControls"
        Title="MainWindow" Height="450" Width="800"
        CanClose="{Binding ElementName=btClosable, Path=IsChecked}">
    <Grid>
        <ToggleButton x:Name="btClosable" Content="Can Close" />
    </Grid>
</win32:NonClosableWindow>

Or by attached Property:

<Window x:Class="BindableCloseButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BindableCloseButton"
        Title="MainWindow" Height="450" Width="800" 
        local:SysMenu.CanClose="{Binding ElementName=btClosable, Path=IsChecked}">
    <Grid>
        <ToggleButton x:Name="btClosable" Content="Can Close" />
    </Grid>
</Window>

Implementation:

public static class SysMenu
{
    public static bool GetCanClose(DependencyObject obj) => (bool)obj.GetValue(CanCloseProperty);
    public static void SetCanClose(DependencyObject obj, bool value) => obj.SetValue(CanCloseProperty, value);

    public static readonly DependencyProperty CanCloseProperty =
        DependencyProperty.RegisterAttached("CanClose", typeof(bool), typeof(SysMenu), 
            new PropertyMetadata(true, CanClose_Changed));

    private static void CanClose_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (DesignerProperties.GetIsInDesignMode(d)) return;
        if (d is not Window w) throw new InvalidOperationException("SysMenu can only be applied to a Window");

        // Avoid duplicates.  Removal is idempotent
        w.Closing -= Window_Closing;
        w.Closing += Window_Closing;

        SetCanCloseInternal(w, (bool)e.NewValue);
    }

    private static void Window_Closing(object? sender, CancelEventArgs e)
    {
        var window = sender as Window ?? throw new InvalidOperationException("SysMenu can only be applied to a Window");
        if (!GetCanClose(window))
        {
            e.Cancel = true;
        }
    }

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

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

    private const uint MF_BYCOMMAND = 0x00000000;
    private const uint MF_GRAYED = 0x00000001;
    private const uint MF_ENABLED = 0x00000000;
    private const uint SC_CLOSE = 0xF060;

    private static void SetCanCloseInternal(Window w, bool value)
    {
        var sysMenu = GetSystemMenu(new WindowInteropHelper(w).Handle, false);
        if (sysMenu == default) return;
        EnableMenuItem(sysMenu, SC_CLOSE, MF_BYCOMMAND | (value ? MF_ENABLED : MF_GRAYED));
    }
}
Mitch
  • 21,223
  • 6
  • 63
  • 86
-1

goto window properties set

window style = none;

u wont get close buttons...

  • Downvote. It's actually `WindowStyle = "None"` - watch your syntax. For another, it is a shotgun approach that also removes the title bar, making the box ugly and lacking a title, when there are so many much better ways to handle this (as evidenced by the other answers), and is a duplicate answer. – vapcguy Mar 21 '17 at 18:11
-1

If the need is only to prohibit the user from closing the window, this is a simple solution.

XAML code: IsCloseButtonEnabled="False"

It's block the button.

-1

After much searching for the answer to this, I worked out this simple solution that I will share here in hopes it helps others.

I set WindowStyle=0x10000000.

This sets the WS_VISIBLE (0x10000000) and WS_OVERLAPPED (0x0) values for Window Style. "Overlapped" is the necessary value to show the title bar and window border. By removing the WS_MINIMIZEBOX (0x20000), WS_MAXIMIZEBOX (0x10000), and WS_SYSMENU (0x80000) values from my style value, all the buttons from the title bar were removed, including the Close button.

mech
  • 2,775
  • 5
  • 30
  • 38
Joe Horr
  • 11
  • 2
  • In WPF `WindowStyle` is an enumeration whose values do not match the Windows API constants; coercing the value to `WindowStyle` enumeration will not work. To be sure, I have checked the .NET source code in ILSpy; the enum value is translated to Windows API in the private function `CreateWindowStyle`, and if the function encounters an unknown `WindowStyle` value, it simply applies `WindowStyle.None`. (The only way would be to use the internal properties `_Style` and `_StyleEx` using reflection, which I strongly recommend against.) – Mike Rosoft Nov 06 '19 at 08:38
-2

Use WindowStyle="SingleBorderWindow" , this will hide max and min button from WPF Window.

wattostudios
  • 8,666
  • 13
  • 43
  • 57
Vishal Nayan
  • 65
  • 1
  • 8