No “Red-X”? Then I can’t close the window! How to achieve this reaction in WPF applications.
Even if it is not always the user friendliest way, there are situation in which you do no want the user to close a window using the “red X” in the upper right corner of a window’s non client area (sometimes only called “Close Button”
).
In most cases this behavior is expected from Dialogs which usually do not have “Minimize” and “Maximize” buttons. So it’s a common practice to hide the whole so called “System Menu”, “Control Box” or “System Bar”.
Windows Forms
It’s quite easy to do so in Windows Forms: Simply set the ControlBox property to false:
public partial class Form1 : Form { public Form1() { InitializeComponent(); //We want to have a dialog this.FormBorderStyle = FormBorderStyle.FixedDialog; //Hide the System Menu / Control Box / System Bar this.ControlBox = false; } }
WPF
However, a Window does not provide a property similar to WinForms’ ControlBox.
First, we set the ResizeMode to NoResize to have an effect like FixedDialog in WinForms:
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="200" Height="75" ResizeMode="NoResize" />
The upper image on the right shows the result. To make it look like on the lower image, we have to use the Windows API:
internal static class Win32 { public const int GWL_STYLE = (-16); public const UInt32 SWP_FRAMECHANGED = 0x0020; public const UInt32 SWP_NOSIZE = 0x0001; public const UInt32 SWP_NOMOVE = 0x0002; public const int WS_SYSMENU = 0x00080000; [DllImport("user32.dll", SetLastError = true)] public static extern int GetWindowLong(IntPtr hWnd, int nIndex); public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong) { if (IntPtr.Size == 8) return SetWindowLongPtr64(hWnd, nIndex, dwNewLong); return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32())); } [DllImport("user32.dll", EntryPoint = "SetWindowLong")] private static extern int SetWindowLong32(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong); [DllImport("user32.dll", SetLastError = true)] public static extern int SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); } internal sealed class CloseButtonHider { private readonly WindowInteropHelper interopHelper; private int windowLong; private bool dirty; public Window Window { get; private set; } public bool IsButtonHidden { get; private set; } private bool IsSourceInitialized { get { return this.WindowHandle != IntPtr.Zero; } } private IntPtr WindowHandle { get { return this.interopHelper.Handle; } } public CloseButtonHider(Window window) { Contract.Requires<ArgumentNullException>(window != null); Contract.Ensures(Object.Equals(this.Window, window)); this.Window = window; this.interopHelper = new WindowInteropHelper(window); if (!this.IsSourceInitialized) this.Window.SourceInitialized += this.Window_SourceInitialized; } public void Hide() { Contract.Ensures(this.IsButtonHidden); if (this.IsButtonHidden) return; this.IsButtonHidden = true; this.ApplyChanges(); } public void Show() { Contract.Ensures(!this.IsButtonHidden); if (!this.IsButtonHidden) return; this.IsButtonHidden = false; this.ApplyChanges(); } private void ApplyChanges() { if (!this.IsSourceInitialized) { this.dirty = true; return; } this.GetWindowLong(); this.SetSysMenu(!this.IsButtonHidden); this.ApplyWindowLong(); this.dirty = false; } private void GetWindowLong() { Contract.Requires(this.IsSourceInitialized); this.windowLong = Win32.GetWindowLong(this.WindowHandle, Win32.GWL_STYLE); } private void ApplyWindowLong() { Contract.Assert(this.IsSourceInitialized); this.SetWindowLong(); this.RefreshWindow(); } private void RefreshWindow() { Contract.Requires(this.IsSourceInitialized); int result = Win32.SetWindowPos(this.WindowHandle, IntPtr.Zero, 0, 0, 100, 100, Win32.SWP_FRAMECHANGED | Win32.SWP_NOMOVE | Win32.SWP_NOSIZE); if (result == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); } private void SetWindowLong() { Contract.Requires(this.IsSourceInitialized); IntPtr result = Win32.SetWindowLongPtr(this.WindowHandle, Win32.GWL_STYLE, new IntPtr(this.windowLong)); if (result == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error()); } private void SetSysMenu(bool value) { this.windowLong = this.windowLong.Set(Win32.WS_SYSMENU, value); } private void Window_SourceInitialized(object sender, EventArgs e) { this.Window.SourceInitialized -= this.Window_SourceInitialized; Contract.Assume(this.IsSourceInitialized); if (this.dirty) this.ApplyChanges(); } [ContractInvariantMethod] private void CloseButtonHiderInvariant() { Contract.Invariant(this.interopHelper != null); Contract.Invariant(this.Window != null); } } internal static class BitExtensions { public static int Set(this int value, int flag) { return BitExtensions.Set(value, flag, true); } public static int Reset(this int value, int flag, bool state) { return BitExtensions.Set(value, flag, false); } public static int Set(this int value, int flag, bool state) { if (state) return value | flag; return value & (~flag); } }
CloseButtonHelper
CloseButtonHelper encapsulates the logic for hiding and restoring the close button. It provides the public methods Show and Hide.
Note that we have to pay attention whether the window has already been created when calling Hide or Show.
Using the new “System.Windows.Interactivity” assembly (brought by Expression Blend 3), we now have the following behavior:
public sealed class HideCloseButtonBehaiviour : Behavior<Window> { private CloseButtonHider hider; protected override void OnAttached() { this.hider = new CloseButtonHider(this.AssociatedObject); this.hider.Hide(); base.OnAttached(); } protected override void OnDetaching() { this.hider.Show(); base.OnDetaching(); } }
Usage
A simple sample Window:
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:WpfApplication1="clr-namespace:WpfApplication1" Title="FooWindow" Width="200" Height="75" ResizeMode="NoResize"> <Interactivity:Interaction.Behaviors> <WpfApplication1:HideCloseButtonBehaiviour /> </Interactivity:Interaction.Behaviors> </Window>
Do you know a simpler way? Please let me know!

July 21, 2009 at 14:24
[WPF] Hide the “Window Buttons” (minimize, restore and close) and the icon of a window…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
July 21, 2009 at 19:37
i have seen that you used contracts. what are your experiences with the static contract checker? i found it rather useless at this point because it misses so many cases.
July 22, 2009 at 14:51
>> what are your experiences with the static contract checker? i found it rather useless at this point because it misses so many cases.
I will cover the static checker in a further part of my “Code Contracts” series.
I totally agree with you: In its current state of development, the static checker is quite useless.
However, there will (hopefully) be lots of improvements and optimizations. Maybe it will be useful in the future.
And I see no disadvantages in using Code Contracts – so I use them.
November 27, 2009 at 21:12
Thanks for this article. It saved me a lot of time
Nice job.
April 30, 2011 at 15:21
if anyone interested, i came across this article that give the ability to disable Maximize and/or Minimize buttons without changing ResizeMode…
Hope it helps.
http://code-in-action.blogspot.com/2009/04/hiding-disabling-maximize-andor.html
March 15, 2012 at 12:35
Try WindowStyle=”None” in your Window XAML. This will remove buttons and title.
March 15, 2012 at 12:42
Try also WindowStyle=”ToolWindow”
June 10, 2012 at 23:49
One way to fix this problem is explained in below link:
http://www.a2zmenu.com/Blogs/Silverlight/WPF-Hide-minimize-button-of-a-window.aspx
August 23, 2012 at 10:11
I do know a simpler way:
//…
this.SourceInitialized += (x, y) =>
{
this.DisableButtons();
};
//…
internal static class WindowExtensions
{
[DllImport("user32.dll")]
internal extern static int SetWindowLong(IntPtr hwnd, int index, int value);
[DllImport("user32.dll")]
internal extern static int GetWindowLong(IntPtr hwnd, int index);
internal static void DisableButtons(this Window window)
{
const int GWL_STYLE = -16;
const int WS_SYSMENU = 0×80000;
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
int value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, value & ~WS_SYSMENU);
}
}
February 7, 2013 at 13:15
Similar to “no___body”s post, there is an article telling this way within the Loaded event of the window – see http://stackoverflow.com/questions/743906/how-to-hide-close-button-in-wpf-window/958980#958980
March 12, 2013 at 20:06
[...] http://winsharp93.wordpress.com/2009/07/21/wpf-hide-the-window-buttons-minimize-restore-and-close-an… [...]