.net 如何在WPF中使用escape键关闭窗口

lvmkulzt  于 2023-03-24  发布在  .NET
关注(0)|答案(6)|浏览(295)

可能重复:

How can I assign the 'Close on Escape-key press' behavior to all WPF windows within a project?
我想在用户单击escape键时关闭wpf项目中的窗口,我不想在每个窗口中都编写代码,但想创建一个类,当用户按下escape键时,它可以捕获。

pprl5pva

pprl5pva1#

备选案文1

使用Button.IsCancel属性。

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

将按钮的IsCancel属性设置为true时,将创建一个在AccessKeyManager中注册的Button。然后,当用户按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();
}
vfhzx4xs

vfhzx4xs2#

这里有一个无按钮的解决方案,它更干净,更像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();
}
cbjzeqam

cbjzeqam3#

在InitializeComponent()后面放一行:

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

请注意,这种代码隐藏不会破坏MVVM模式,因为这是与UI相关的,并且您不访问任何视图模型数据。替代方法是使用附加属性,这将需要更多代码。

1tuwyuhd

1tuwyuhd4#

您可以创建自定义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();
            }
        }
    }
}

并像这样使用Windows的XAML:

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

答案基于this answer中引用的要点的内容。

qyzbxkaa

qyzbxkaa5#

这里的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();
    }
}
kmb7vmvb

kmb7vmvb6#

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

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

相关问题