如何在WPF中使用ESC键关闭窗口

61

那不是我的解决方案... 我甚至不想在每个窗口中都做<Window.InputBinding>,我想将其写入样式中,但由于<Window.InputBinding>属性在样式中不可用,所以无法实现。 - Kishore Kumar
看看这个帖子 - 它详细解释了如何实现此功能。 - Steve Greatrex
这是 https://dev59.com/O3RC5IYBdhLWcg3wD87r 的副本。 - Micha Wiedenmann
可能是How does the WPF Button.IsCancel property work?的重复问题。 - Cœur
6个回答

162

选项1

使用Button.IsCancel属性。

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

当你将按钮的IsCancel属性设置为true时,你创建了一个已向AccessKeyManager注册的按钮。当用户按ESC键时,该按钮会被激活。

然而,这只对对话框有效。

选项2

如果你想要在按下Esc键时关闭窗口,可以在窗口上添加PreviewKeyDown的处理程序。

public MainWindow()
{
    InitializeComponent();

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

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

3
我不想使用按钮……无论如何,感谢你,我找到了解决方案。 - Kishore Kumar
2
@kishorejangid - 你能在这里发布你的答案吗? - Rohit Vats
1
你可以在按钮上设置IsDefault="True",这样按回车键就相当于点击了按钮。 - PerK
@KishoreKumar 我需要通过键绑定关闭用户控件,但不使用在按钮中设置 IsCancel 属性的方法。 - sameer
如果您使用无窗口的WPF表单进行设计,那么在表单中会有一个“关闭”按钮。只需在Xaml中找到该按钮控件,并将其IsCancel属性更新为true即可。 - Chandraprakash
显示剩余2条评论

16

这是一个无需按钮的解决方案,简洁并更符合MVVM思想。将以下XAML添加到您的对话框/窗口中:

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

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

并在代码后台处理该事件:

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

10
在InitializeComponent()后添加一行代码:
 PreviewKeyDown += (s,e) => { if (e.Key == Key.Escape) Close() ;};

请注意,这种代码后台不会破坏MVVM模式,因为这与UI相关且您不会访问任何viewmodel数据。另一种选择是使用附加属性,这将需要更多的代码。

1
这里的InputBinding选项非常好用且灵活。
如果你想使用事件处理程序,请注意Preview事件发生得非常早。如果你有一个嵌套控件应该为自己的目的使用Esc键,那么在窗口级别夺取它可能会破坏该控件的功能。
相反,只有在没有其他东西想要处理该事件时,你才能在窗口级别处理该事件:
protected override void OnKeyDown(KeyEventArgs e)
{
    base.OnKeyDown(e);

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

1
你可以创建自定义的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"
    ...>

答案基于引用的要点内容,参见this answer

-1

添加一个IsCancel="True"的按钮,但宽度和高度为0(用于隐藏)

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接