Introduction
One of the things I’ve had to do over the years is remove the Close box from a WPF window, in order to create a tools or response-type window that the user can only exit by selecting one of the buttons that I provide him. I use it so frequently that I eventually created my own class, inherited from the Window
class, that contains the extra functionality.
NOTE: This solution is aimed at windows with the Style of ToolWindow
… it simply removes the close button in the upper-right corner in order to control more tightly how exit from the window is accomplished.
Keep in mind also that this solution will work for any windows, not just those with a ToolWindow
style, EXCEPT that it will also remove the minimize and maximize buttons.
Using the Code
This is a walkthrough of the process for creating a WPF ToolWindow
, using a brand-new project as an example. Simply follow the steps outlined here to make it work.
The project I created was called SampleRemoveCloseBox
, and that was also the name of the namespace.
First, create a new WPF project, and add a single button to close the program. The XAML should look like this:
//
// XAML Code, window with close button
//
<Window x:Class="SampleRemoveCloseBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350"
Width="525" WindowStyle="ToolWindow">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Name="btnClose" Margin="5,5,5,5"
Click="btnClose_Click">Close the Program</Button>
</Grid>
</Window>
...
And the program when run looks like this:
The goal is to remove the close box in the upper right corner, so that the only way to exit the program is by pressing the button.
In the code-behind, create the class for the window.
public partial class CustomWindow : Window
{
private const int GWL_STYLE = -16;
private const int WS_SYSMENU = 0x80000;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
public CustomWindow()
{
Loaded += ToolWindow_Loaded;
}
void ToolWindow_Loaded(object sender, RoutedEventArgs e)
{
var hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
}
}...
This is the code that removes the close button. If you want to do this without the custom class, just place the prep stuff in your window class, and then the actual code in the loaded
event for your window.
But to continue this tutorial, change the window definition to inherit from this class instead of window.
public partial class MainWindow : CustomWindow
{
public MainWindow()
{
InitializeComponent();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
Close();
}
}
...
Now change the XAML to also inherit from that class instead of window.
//
// XAML Code, window is of CustomWindow class
//
<local:CustomWindow x:Class="SampleRemoveCloseBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SampleRemoveCloseBox"
Title="MainWindow" Height="350"
Width="525" WindowStyle="ToolWindow">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Name="btnClose" Margin="5,5,5,5"
Click="btnClose_Click">Close the Program</Button>
</Grid>
</local:CustomWindow>...
And now the program when run looks like this:
Notice that the close button is gone from the upper right corner of the program. This can be used for popup dialog boxes for which a response is required, or any kind of a data entry window where the user should use the provided methods to leave the window. Basically, it is useful anywhere you use a ToolWindow
.
The title bar is not strictly under WPF control, so what you can do with it is limited. Because of that, you need to set the window style using WIN32 calls, but they work well enough.
And that's all there is to it. A pretty simple solution, even though it is incredibly NOT intuitively obvious.
Points of Interest
For a long time, I simply dropped the relevant code onto any form I needed it on, but eventually I did create a CustomWindow
class that automatically included that functionality, making it even easier to implement this solution.
History
- 2016-11-09 -- Original version