programing

WPF 페이지 또는 UserControl 개체에서 KeyDown 이벤트를 캡처하려면 어떻게 해야 합니까?

showcode 2023. 4. 15. 09:41
반응형

WPF 페이지 또는 UserControl 개체에서 KeyDown 이벤트를 캡처하려면 어떻게 해야 합니까?

사용자 컨트롤이 있는 페이지가 있습니다.사용자가 처리하고자 하는 페이지에서 Esc 키를 누른 경우.

PreviewKeyDown 이벤트 후크업, Esc 키 테스트, 처리처럼 간단하다고 생각했습니다.그러나 이벤트 핸들러에 브레이크 포인트를 배치했을 때 호출되지 않았습니다.UserControl이 히트하고 있는 것 같아서 PreviewKeyDown을 시도했습니다.같은 결과입니다.

페이지 오브젝트에서 KeyDown 또는 PreviewKeyDown을 테스트하는 적절한 장소를 알고 있는 사람이 있습니까?

창의 이벤트에 연결

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」KeyDown의 이벤트)를 사용합니다.Window.GetWindow(this)다음과 같이 합니다.

XAML

<UserControl Loaded="UserControl_Loaded">
</UserControl>

이면의 코드

private void UserControl_Loaded(object sender, RoutedEventArgs e) {
  var window = Window.GetWindow(this);
  window.KeyDown += HandleKeyPress;
}

private void HandleKeyPress(object sender, KeyEventArgs e) {
  //Do work
}

나도 같은 문제가 있었다.다양한 페이지로 로드/내비게이트하는 프레임을 호스트하는 창이 있으며, 이 창에는 일반 컨트롤/요소(라벨, 하이퍼링크 등)가 포함된 사용자 컨트롤이 하나만 포함됩니다.

내가 발견한 것(물론 몇 시간 동안의 좌절 후에!!!)위의 컨트롤/요소에 포커스가 없는 경우 PreviewKeyDown 이벤트는 UserControl(프레임레벨의 어딘가에 정지)에서 실행되지 않고 포커스를 두는 즉시(예를 들어 ctrl을 호출하는 경우) 실행됩니다.UserCotrol의 Loaded 이벤트 핸들러 내의 Focus() 컨트롤 중 하나의 마법이 발생하여 동작하며 UserControl에서도 이벤트가 실행됩니다.

물론 나중에 생각하면 충분히 말이 되지만, 적어도 10명 중 5명은 깜짝 놀랄 거라고 100% 확신해:) WPF라고 불리는 말도 안 되는 작은 것...

건배!

PreviewKeyDown 이벤트는 버블링 이벤트가 아니라 터널링 라우팅 이벤트라고 생각합니다.이 경우 페이지가 이벤트를 수신할 수 없는 경우 UserControl은 시각적 트리의 페이지 아래에 있으므로 둘 다 수신할 수 없습니다.앱의 최상위 레벨(윈도?)에서 이벤트를 받을 수 있는지 확인해 보십시오.

CodePlex의 Snoop과 같은 기능을 사용하여 이벤트의 진행 위치를 파악하는 것도 도움이 될 수 있습니다.

UserControl에서 Focusable 속성을 true로 설정하면 문제가 해결되었습니다.

@Doc을 강화하는 방법을 제안합니다.

가 가장 바깥쪽의 KeyDown으로 합니다.Window한 번.한번만Window는 내부인 "" 에서 버블된 KeyDown 합니다.Window된 모든 됩니다.를 들어 다음과 같습니다.HandleKeyPress.

private void UserControl_Loaded(object sender, RoutedEventArgs e) {
  var window = Window.GetWindow(this);
  window.KeyDown += HandleKeyPress;
}

private void HandleKeyPress(object sender, KeyEventArgs e) {
  //Do work
}

★★★★★★★★★★★★★★★.+=위험합니다.프로그래머는 이벤트 매니저의 등록 해제를 잊어버릴 가능성이 높습니다.메모리 누전이나 버그가 발생합니다.

여기서 제안합니다.

YourWindow.xaml.cs

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

    // You need to have a reference to YourUserControlViewModel in the class.
    YourUserControlViewModel.CallKeyDown(e);

    // Or, if you don't like ViewModel, hold your user-control in the class then
    YourUserControl.CallKeyDown(e);
}

YourUserControlViewModel.cs 또는 YourUserControl.xaml.cs

public void CallKeyDown(KeyEventArgs e) {
  //Do your work
}

xaml로 코드화할 필요는 없습니다.

나에게 정확히 효과가 있었던 것:

창 Loaded 이벤트만 PreviewKeyDown 이벤트를 듣습니다.

void GameScreen_Loaded(object sender, RoutedEventArgs e)
{
     this.PreviewKeyDown += GameScreen_PreviewKeyDown;
     this.Focusable = true;
     this.Focus();
}

void GameScreen_PreviewKeyDown(object sender, KeyEventArgs e)
{
     MessageBox.Show("it works!");   
}

WinForms에서 WPF 창을 호출했을 때도 같은 문제가 있었습니다.KeyDown 이벤트와 PreviewKeyDown 이벤트 모두 실행되지 않았습니다.

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.Show();

그러나 창을 대화상자로 표시하여 작동했다.

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.ShowDialog();

PreviewKeyDown 이벤트가 이스케이프 키와 화살표 키에 대한 부적처럼 발생하였습니다.

void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Escape:
                    this.Close();
                    break;
                case Key.Right:
                    page_forward();
                    break;
                case Key.Left:
                    page_backward();
                    break;
            }
        }

이게 먹히길 바라.

창의 이벤트에 첨부하지 않으려면 UserControl 또는 페이지의 변경 내용을 볼 수 있도록 이벤트를 추가하십시오.

IsVisibleChanged="Page_IsVisibleChanged"

그 후 코드 배후에:

private void Page_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if(this.Visibility == Visibility.Visible)
            {
                this.Focusable = true;
                this.Focus();
            }
        }

아무 키나 누르면 KeyDown 이벤트가 발생합니다.

.Weindow_KeyDown

여기 예가 있다

private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            // ... Test for F1 key.
            if (e.Key == Key.F1)
            {
                this.Title = "You pressed F1 key";
            }
        }

꼭 해 주세요.Weindow_KeyDown

<Window x:Class="WpfApplication25.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        KeyDown="Window_KeyDown">
</Window>

@Daniel 솔루션 대신 다음 작업을 수행합니다.이 솔루션에서는 윈도 전체에 이벤트 핸들러를 추가할 필요가 없습니다.

public partial class MyControl : UserControl{

public MyControl()
{
   MouseEnter+= MouseEnterHandler;
   MouseLeave+= MouseLeaveHandler;
}

protected void MouseEnterHandler(object sender, MouseEventArgs e)
{
   var view = sender as MyControl;
   view.KeyDown += HandleKeyPress;
   view.KeyUp += HandleKeyReleased;
   view.Focus();
}

protected void MouseLeaveHandler(object sender, MouseEventArgs e)
{
   var view = sender as MyControl;
   view.KeyDown -= HandleKeyPress;
   view.KeyUp -= HandleKeyReleased;
}

protected void HandleKeyPress(object sender, KeyEventArgs e)
{
    // What happens on key pressed
}

protected void HandleKeyReleased(object sender, KeyEventArgs e)
{
    // What happens on key released
}

}

이렇게 하면 보기의 다른 부분에서 동일한 이벤트의 다른 핸들을 가질 수 있습니다.핸들은 로컬이며 컨트롤에 고유하며 전역 창에 핸들을 추가하지 않습니다.

ElementHost를 사용하여 창을 활성화해 보십시오.EnableModelessKeyboard상호 운용.이 경우 키다운 이벤트에서 화살표 키를 캡처합니다.

전화로 이 문제를 해결했습니다.뷰의 버튼에 포커스()를 붙여 창이 모든 요소의 로드를 완료했는지 확인합니다.

사용자 제어에 이니셜라이저가 있습니다.뒤에 있는 코드에 핸들러를 추가합니다.XAML에서는 아무것도 할 필요가 없습니다.

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        KeyDown += Handle_KeyDown;
    }

    private void Handle_KeyDown(object sender, KeyEventArgs e)
    {
        throw new NotImplementedException();
    }
}

온로드 이벤트는 필요 없습니다.이니셜라이저에 포함되어 있습니다.또한 모든 것을 한 파일에 보관하면 유지보수가 쉬워집니다.

다른 사용자가 언급했듯이 필요에 따라 PreviewKeyDown이 KeyDown보다 더 유용할 수 있습니다.

이것은 테스트 완료이며, 확실히 동작합니다.

  Private Sub textbox1_PreviewKeyDown(sender As Object, e As KeyEventArgs) Handles textbox1_input.PreviewKeyDown
        If (e.Key = Key.Down) Then
            MessageBox.Show("It works.")
        End If
    End Sub

'detect key state directly with something like this below
 Dim x As KeyStates = System.Windows.Input.Keyboard.GetKeyStates(Key.Down)

PreviewKeyDown은 대부분의 사람들이 놓치는 것입니다.PreviewKeyDown은 키보드이벤트의 전체적인 옵서버라고 생각하시면 됩니다(단, 틀리지 않으면 영향을 줄 수 없습니다).또, KeyDown event는, 현재 사용하고 있는 컨트롤이나 클래스의 범위내에서 재생되고 있습니다.

언급URL : https://stackoverflow.com/questions/347724/how-can-i-capture-keydown-event-on-a-wpf-page-or-usercontrol-object

반응형