61

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.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
Kishore Kumar
  • 12,675
  • 27
  • 97
  • 154
  • that's not my solution.. I dont even want the to be done in every window. I want to write that in a Style but thats not working as Propety is not available in Style – Kishore Kumar Oct 07 '11 at 19:32
  • Check out [this][1] post - it explains exactlyhow to achieve this [1]: http://stackoverflow.com/questions/3863431/how-can-i-assign-the-close-on-escape-key-press-behavior-to-all-wpf-windows-with – Steve Greatrex Oct 08 '11 at 14:05
  • This is a duplicate of http://stackoverflow.com/questions/419596/how-does-the-wpf-button-iscancel-property-work – Micha Wiedenmann Nov 02 '15 at 12:10
  • Possible duplicate of [How does the WPF Button.IsCancel property work?](https://stackoverflow.com/questions/419596/how-does-the-wpf-button-iscancel-property-work) – Cœur Jul 14 '18 at 11:09

6 Answers6

162

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();
}
CharithJ
  • 46,289
  • 20
  • 116
  • 131
15

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();
}
dotNET
  • 33,414
  • 24
  • 162
  • 251
10

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.

Alexandru Dicu
  • 1,151
  • 1
  • 16
  • 24
1

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.

qqbenq
  • 10,220
  • 4
  • 40
  • 45
1

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();
    }
}
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
-1

Add Button with IsCancel="True", but Width and Height is 0 (for hidden)

<Button Width="0" Height="0" IsCancel="True"/>