How to Close a Window in WPF on a escape key

Option 1

Use Button.IsCancel property.

<Button Name="btnCancel" IsCancel="true" Click="OnClickCancel">Cancel</Button>

When you set the IsCancel property of a button to true, you create a Button that is registered with the AccessKeyManager. The button is then activated when a user presses the ESC key.

However, this works properly only for Dialogs.

Option2

You add a handler to PreviewKeyDown on the window if you want to close windows on Esc press.

public MainWindow()
{
    InitializeComponent();

    this.PreviewKeyDown += new KeyEventHandler(HandleEsc);
}

private void HandleEsc(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Escape)
        Close();
}

Here is a button-less solution that is clean and more MVVM-ish. Add the following XAML into your dialog/window:

<Window.InputBindings>
  <KeyBinding Command="ApplicationCommands.Close" Key="Esc" />
</Window.InputBindings>

<Window.CommandBindings>
  <CommandBinding Command="ApplicationCommands.Close" Executed="CloseCommandBinding_Executed" />
</Window.CommandBindings>

and handle the event in the code-behind:

private void CloseCommandBinding_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
  if (MessageBox.Show("Close?", "Close", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
    this.Close();
}

One line to put after InitializeComponent():

 PreviewKeyDown += (s,e) => { if (e.Key == Key.Escape) Close() ;};

Please note that this kind of code behind does not break MVVM pattern since this is UI related and you don't access any viewmodel data. The alternative is to use attached properties which will require more code.


You can create a custom DependencyProperty:

using System.Windows;
using System.Windows.Input;

public static class WindowUtilities
{
    /// <summary>
    /// Property to allow closing window on Esc key.
    /// </summary>
    public static readonly DependencyProperty CloseOnEscapeProperty = DependencyProperty.RegisterAttached(
       "CloseOnEscape",
       typeof(bool),
       typeof(WindowUtilities),
       new FrameworkPropertyMetadata(false, CloseOnEscapeChanged));

    public static bool GetCloseOnEscape(DependencyObject d)
    {
        return (bool)d.GetValue(CloseOnEscapeProperty);
    }

    public static void SetCloseOnEscape(DependencyObject d, bool value)
    {
        d.SetValue(CloseOnEscapeProperty, value);
    }

    private static void CloseOnEscapeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is Window target)
        {
            if ((bool)e.NewValue)
            {
                target.PreviewKeyDown += Window_PreviewKeyDown;
            }
            else
            {
                target.PreviewKeyDown -= Window_PreviewKeyDown;
            }
        }
    }

    private static void Window_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (sender is Window target)
        {
            if (e.Key == Key.Escape)
            {
                target.Close();
            }
        }
    }
}

And use it your windows' XAML like this:

<Window ...
    xmlns:custom="clr-namespace:WhereverThePropertyIsDefined"
    custom:WindowUtilities.CloseOnEscape="True"
    ...>

The answer is based on the content of the gist referenced in this answer.