programing

이스케이프 키로 WPF 창을 닫는 방법

testmans 2023. 4. 20. 20:08
반응형

이스케이프 키로 WPF 창을 닫는 방법

중복 가능성:
프로젝트 내의 모든 WPF 창에 '탈옥 키 누름 시 닫기' 동작을 할당하려면 어떻게 해야 합니까?

사용자가 이스케이프 버튼을 클릭했을 때 wpf 프로젝트에서 창을 닫고 싶다.모든 창에 코드를 쓰는 것이 아니라 사용자가 이스케이프 키를 누르면 잡을 수 있는 클래스를 만들고 싶습니다.

옵션 1

버튼을 사용합니다.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();
}

다음은 버튼이 필요 없는 솔루션으로 깔끔하고 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();
}

Initialize Component() 뒤에 넣을 행:

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

UI와 관련된 것으로 뷰 모델 데이터에 액세스 할 수 없기 때문에 뒤에 있는 이러한 종류의 코드는 MVVM 패턴을 깨지 않습니다.또 다른 방법은 추가 코드가 필요한 첨부된 속성을 사용하는 것입니다.

커스텀 Dependency Property를 생성할 수 있습니다.

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

윈도우의 XAML을 다음과 같이 사용합니다.

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

이 답변은 이 답변에서 언급된 요지의 내용을 기반으로 합니다.

InputBinding이 옵션에는 유연성이 있습니다.

이벤트 핸들러를 사용하는 경우는,Preview사건은 꽤 일찍 일어난다.키를 자체 용도로 사용해야 하는 중첩된 컨트롤이 있는 경우, 윈도우 수준에서 키를 훔치면 해당 컨트롤의 기능이 중단될 수 있습니다.

대신, 창 수준에서 이벤트를 처리할 수 있는 것은 다음과 같은 경우뿐입니다.

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

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

IsCancel=을 사용하여 버튼 추가"참"이지만 폭과 높이는 0입니다(숨김의 경우).

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

언급URL : https://stackoverflow.com/questions/7691713/how-to-close-a-window-in-wpf-on-a-escape-key

반응형