How to Close a Window in WPF on a escape key

C#.NetWpfXaml

C# Problem Overview


> Possible Duplicate:
> How can I assign the 'Close on Escape-key press' behavior to all WPF windows within a project?

I want to close the windows in my wpf project when the user clicks the escape button. I don't want to write the code in every window but want to create a class which can catch the when the user press the escape key.

C# Solutions


Solution 1 - C#

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

Solution 2 - C#

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

Solution 3 - C#

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.

Solution 4 - C#

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.

Solution 5 - C#

The InputBinding options here are nice and flexible.

If you want to use an event handler, be aware that the Preview events happen quite early. If you have a nested control that should take the Esc key for its own purposes, stealing it at the window level may brake that control's functionality.

Instead you can handle the event at the window level only if nothing else wants to with:

protected override void OnKeyDown(KeyEventArgs e)
{
    base.OnKeyDown(e);

    if (!e.Handled && e.Key == Key.Escape && Keyboard.Modifiers == ModifierKeys.None)
    {
        this.Close();
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKishore KumarView Question on Stackoverflow
Solution 1 - C#CharithJView Answer on Stackoverflow
Solution 2 - C#dotNETView Answer on Stackoverflow
Solution 3 - C#Alexandru DicuView Answer on Stackoverflow
Solution 4 - C#qqbenqView Answer on Stackoverflow
Solution 5 - C#Drew NoakesView Answer on Stackoverflow