입력 개요

WPF(Windows Presentation Foundation)하위 시스템은 마우스, 키보드, 터치 및 스타일러스를 비롯 한 다양 한 장치에서 입력을 얻기 위한 강력한 API를 제공 합니다. 이 항목에서는 WPF가 제공하는 서비스에 대해 설명하고 입력 시스템의 아키텍처를 살펴봅니다.

입력 API

기본 입력 API 노출은 기본 요소 클래스인,, 및에 있습니다 UIElement ContentElement FrameworkElement FrameworkContentElement . 기본 요소에 대한 자세한 내용은 기본 요소 개요를 참조하세요. 이러한 클래스는 키 누르기, 마우스 단추, 마우스 휠, 마우스 이동, 포커스 관리, 마우스 캡처 등과 관련된 입력 이벤트를 위한 기능을 제공합니다. 입력 아키텍처를 사용 하면 입력 이벤트를 모든 입력 이벤트를 서비스로 처리 하는 대신 기본 요소에 배치 하 여 입력 이벤트를 UI의 특정 개체에서 원본으로 지정할 수 있으며, 둘 이상의 요소가 입력 이벤트를 처리할 기회가 있는 이벤트 라우팅 체계를 지원할 수 있습니다. 대부분의 입력 이벤트에는 연결된 이벤트 쌍이 있습니다. 예를 들어 key down 이벤트는 및 이벤트와 연결 KeyDown 됩니다 PreviewKeyDown . 이벤트마다 이벤트가 대상 요소로 라우트되는 방법이 다릅니다. 미리 보기 이벤트는 요소 트리의 루트 요소에서 대상 요소로 터널링됩니다. 버블링 이벤트는 대상 요소에서 루트 요소로 버블링됩니다. WPF의 이벤트 라우팅에 대한 자세한 내용은 이 개요 항목의 이후 단원 및 라우트된 이벤트 개요에서 자세히 설명합니다.

키보드 및 마우스 클래스

기본 요소 클래스의 입력 API 외에도 Keyboard 클래스와 Mouse 클래스는 키보드 및 마우스 입력을 사용 하기 위한 추가 api를 제공 합니다.

클래스에 대 한 입력 API의 예로는 Keyboard Modifiers 현재 누른을 반환 하는 속성과 ModifierKeys 지정 된 키를 IsKeyDown 눌렀는지 여부를 결정 하는 메서드가 있습니다.

다음 예제에서는 메서드를 사용 하 여 GetKeyStates 이 다운 상태 인지 여부를 확인 합니다 Key .

// Uses the Keyboard.GetKeyStates to determine if a key is down.
// A bitwise AND operation is used in the comparison.
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
    btnNone.Background = Brushes.Red;
}
' Uses the Keyboard.GetKeyStates to determine if a key is down.
' A bitwise AND operation is used in the comparison. 
' e is an instance of KeyEventArgs.
If (Keyboard.GetKeyStates(Key.Return) And KeyStates.Down) > 0 Then
    btnNone.Background = Brushes.Red

클래스의 입력 API 예는 마우스 Mouse MiddleButton 가운데 단추의 상태를 가져오는 이며 DirectlyOver 마우스 포인터가 현재 있는 요소를 가져오는입니다.

다음 예에서는 LeftButton 마우스의가 상태에 있는지 여부를 확인 합니다 Pressed .

if (Mouse.LeftButton == MouseButtonState.Pressed)
{
    UpdateSampleResults("Left Button Pressed");
}
If Mouse.LeftButton = MouseButtonState.Pressed Then
    UpdateSampleResults("Left Button Pressed")
End If

Mouse Keyboard 이 개요 전체에서 및 클래스에 대해 자세히 설명 합니다.

스타일러스 입력

WPF 에는에 대 한 통합 지원이 있습니다 Stylus . 는 Stylus TABLET PC에서 널리 사용 되는 펜 입력입니다. WPF 응용 프로그램은 마우스 API를 사용 하 여 스타일러스를 마우스로 처리할 수 있지만 WPF 키보드 및 마우스와 유사한 모델을 사용 하는 스타일러스 장치 추상화도 노출 합니다. 모든 스타일러스 관련 Api는 "스타일러스" 라는 단어를 포함 합니다.

스타일러스는 마우스처럼 동작할 수 있으므로 마우스 입력만 지원하는 애플리케이션도 약간의 스타일러스 지원을 자동으로 받을 수 있습니다. 이러한 방식으로 스타일러스를 사용하는 경우 애플리케이션은 알맞은 스타일러스 이벤트를 처리한 다음 해당 마우스 이벤트를 처리할 수 있게 됩니다. 뿐만 아니라 스타일러스 디바이스 추상화를 통해 잉크 입력과 같은 높은 수준의 서비스도 사용할 수 있습니다. 잉크 입력에 대한 자세한 내용은 잉크 시작을 참조하세요.

이벤트 라우팅

FrameworkElement 다른 요소를 콘텐츠 모델의 자식 요소로 포함 하 여 요소의 트리를 형성할 수 있습니다. WPF에서 부모 요소는 이벤트를 처리하여 해당 자식 요소 또는 다른 하위 요소를 대상으로 하는 입력에 참가할 수 있습니다. 이는 특히 더 작은 컨트롤에서 컨트롤을 빌드하는 “컨트롤 컴퍼지션” 또는 “합치기”라고 하는 프로세스에 유용합니다. 요소 트리 및 요소 트리와 이벤트 경로가 서로 어떻게 관련되는지에 대한 자세한 내용은 WPF의 트리를 참조하세요.

이벤트 라우팅은 이벤트를 여러 요소로 전달함으로써 경로 상의 특정 개체나 요소가 다른 요소에서 발생시킨 이벤트에 대해 이벤트 처리를 통해 의미 있는 응답을 제공할 수 있도록 하는 프로세스입니다. 라우트된 이벤트는 직접, 버블링, 터널링이라는 세 가지 라우팅 메커니즘 중 하나를 사용합니다. 직접 라우팅에서는 소스 요소만 이벤트에 대한 알림을 받으며 이벤트가 다른 요소로 라우트되지 않습니다. 그러나 직접 라우트된 이벤트는 표준 CLR 이벤트와는 달리 라우트된 이벤트에 대해서만 제공 되는 몇 가지 추가 기능을 제공 합니다. 버블링은 먼저 이벤트에 대해 이벤트를 발생시킨 요소에 알린 다음 부모 요소 등에 알리는 순서로 요소 트리의 위쪽으로 작동합니다. 터널링은 요소 트리의 루트에서 시작하여 아래로 이동한 다음 원래 소스 요소에서 끝납니다. 라우트된 이벤트에 대한 자세한 내용은 라우트된 이벤트 개요를 참조하세요.

WPF 입력 이벤트는 일반적으로 터널링 이벤트와 버블링 이벤트의 쌍으로 구성되어 제공됩니다. 터널링 이벤트는 “Preview” 접두사가 있다는 점에서 버블링 이벤트와 다릅니다. 예를 들어 PreviewMouseMove 는 마우스 이동 이벤트의 터널링 버전 이며 MouseMove 이 이벤트의 버블링 버전입니다. 이 이벤트 쌍은 요소 수준에서 구현되는 규칙이며 WPF 이벤트 시스템의 본질적인 기능은 아닙니다. 자세한 내용은 라우트된 이벤트 개요의 WPF 입력 이벤트 섹션을 참조하세요.

입력 이벤트 처리

요소에서 입력을 받으려면 특정 이벤트에 이벤트 처리기를 연결해야 합니다. XAML에서는 이 작업이 매우 간단합니다. 이 이벤트를 수신할 요소의 특성으로 이벤트 이름을 참조합니다. 그런 다음 대리자에 따라 정의하는 이벤트 처리기의 이름으로 특성 값을 설정하기만 하면 됩니다. 이벤트 처리기는 c #과 같은 코드에 작성 되어야 하 고 코드 숨김이 포함 된 파일에 포함 될 수 있습니다.

키보드 이벤트는 키보드 포커스가 요소에 있는 동안 발생하는 키 동작을 운영 체제에서 보고할 때 발생합니다. 마우스 및 스타일러스 이벤트는 각각 요소를 기준으로 포인터 위치의 변경을 보고하는 이벤트와 디바이스 단추의 상태 변경을 보고하는 이벤트의 두 범주로 나뉩니다.

키보드 입력 이벤트 예제

다음 예제에서는 왼쪽 화살표 키 누르기를 수신합니다. 이 있는가 StackPanel 만들어집니다 Button . 왼쪽 화살표 키 누름을 수신 대기 하는 이벤트 처리기가 인스턴스에 연결 됩니다 Button .

예제의 첫 번째 섹션에서는 및을 만들고 StackPanel Button 에 대 한 이벤트 처리기를 연결 합니다 KeyDown .

<StackPanel>
  <Button Background="AliceBlue"
          KeyDown="OnButtonKeyDown"
          Content="Button1"/>
</StackPanel>
// Create the UI elements.
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();

// Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";

// Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1);

// Attach event handler.
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);
' Create the UI elements.
Dim keyboardStackPanel As New StackPanel()
Dim keyboardButton1 As New Button()

' Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue
keyboardButton1.Content = "Button 1"

' Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1)

' Attach event handler.
AddHandler keyboardButton1.KeyDown, AddressOf OnButtonKeyDown

코드로 작성된 두 번째 섹션은 이벤트 처리기를 정의합니다. 왼쪽 화살표 키를 누르면에 Button 키보드 포커스가 있으면 처리기가 실행 Background 되 고의 색 Button 이 변경 됩니다. 키를 누른 채 왼쪽 화살표 키가 아닌 경우 Background 의 색은 Button 다시 시작 색으로 변경 됩니다.

private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
    Button source = e.Source as Button;
    if (source != null)
    {
        if (e.Key == Key.Left)
        {
            source.Background = Brushes.LemonChiffon;
        }
        else
        {
            source.Background = Brushes.AliceBlue;
        }
    }
}
Private Sub OnButtonKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
    Dim source As Button = TryCast(e.Source, Button)
    If source IsNot Nothing Then
        If e.Key = Key.Left Then
            source.Background = Brushes.LemonChiffon
        Else
            source.Background = Brushes.AliceBlue
        End If
    End If
End Sub

마우스 입력 이벤트 예제

다음 예제에서는 Background 마우스 포인터가로 들어가면의 색 Button 이 변경 됩니다 Button . Background이 색은 마우스가을 벗어날 때 복원 됩니다 Button .

예제의 첫 번째 섹션에서는 StackPanel 및 컨트롤을 만들고 Button 및 이벤트에 대 한 이벤트 처리기를에 연결 MouseEnter MouseLeave Button 합니다.

<StackPanel>
  <Button Background="AliceBlue"
          MouseEnter="OnMouseExampleMouseEnter"
          MouseLeave="OnMosueExampleMouseLeave">Button
          
  </Button>
</StackPanel>
// Create the UI elements.
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();

// Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";

// Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton);

// Attach event handler.
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);
' Create the UI elements.
Dim mouseMoveStackPanel As New StackPanel()
Dim mouseMoveButton As New Button()

' Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue
mouseMoveButton.Content = "Button"

' Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton)

' Attach event handler.
AddHandler mouseMoveButton.MouseEnter, AddressOf OnMouseExampleMouseEnter
AddHandler mouseMoveButton.MouseLeave, AddressOf OnMosueExampleMouseLeave

예제에서 코드로 작성된 두 번째 섹션은 이벤트 처리기를 정의합니다. 마우스가에 들어가면의 Button BackgroundButton 이로 변경 됩니다 SlateGray . 마우스로 벗어나면의 Button BackgroundButton 이로 다시 변경 됩니다 AliceBlue .

private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.SlateGray;
    }
}
Private Sub OnMouseExampleMouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs)
    ' Cast the source of the event to a Button.
    Dim source As Button = TryCast(e.Source, Button)

    ' If source is a Button.
    If source IsNot Nothing Then
        source.Background = Brushes.SlateGray
    End If
End Sub
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.AliceBlue;
    }
}
Private Sub OnMosueExampleMouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs)
    ' Cast the source of the event to a Button.
    Dim source As Button = TryCast(e.Source, Button)

    ' If source is a Button.
    If source IsNot Nothing Then
        source.Background = Brushes.AliceBlue
    End If
End Sub

텍스트 입력

TextInput이벤트를 사용 하면 장치 독립적 방식으로 텍스트 입력을 수신할 수 있습니다. 텍스트 입력에는 주로 키보드를 사용하지만 음성, 필기 및 기타 입력 디바이스를 통해서도 텍스트 입력을 생성할 수 있습니다.

키보드 입력의 경우는 WPF 먼저 적절 한 이벤트를 보냅니다 KeyDown / KeyUp . 이러한 이벤트가 처리 되지 않고 키가 방향 화살표 또는 기능 키와 같은 컨트롤 키가 아닌 텍스트 이면 TextInput 이벤트가 발생 합니다. KeyDown / KeyUp TextInput 여러 키 입력에서 단일 텍스트 입력 문자를 생성할 수 있고 단일 키 입력이 여러 문자로 된 문자열을 생성할 수 있기 때문에 및 이벤트 간에 간단한 일대일 매핑이 항상 발생 하는 것은 아닙니다. 이는 Ime (입력기)를 사용 하 여 해당 하는 알파벳에서 수천 개의 문자를 생성 하는 중국어, 일본어, 한국어 등의 언어에서 특히 그렇습니다.

WPF에서 이벤트를 보낼 때 KeyUp / KeyDown Key Key.System 키 입력이 이벤트의 일부가 될 수 있으면가로 설정 됩니다 TextInput (예: ALT + S를 누른 경우). 이를 통해 이벤트 처리기의 코드에서를 KeyDown 확인 하 Key.System 고, 검색 된 경우 이후에 발생 한 이벤트 처리기에 대 한 처리를 유지할 수 있습니다 TextInput . 이러한 경우 인수의 다양 한 속성을 TextCompositionEventArgs 사용 하 여 원래 키 입력을 확인할 수 있습니다. 마찬가지로 IME가 활성 상태인 경우에는 Key 의 값이이 Key.ImeProcessedImeProcessedKey 원래 키 입력 또는 키 입력을 제공 합니다.

다음 예제에서는 이벤트에 대 한 처리기 및 이벤트에 대 한 처리기를 정의 합니다 Click KeyDown .

코드 또는 태그의 첫 번째 세그먼트에서는 사용자 인터페이스를 만듭니다.

<StackPanel KeyDown="OnTextInputKeyDown">
  <Button Click="OnTextInputButtonClick"
          Content="Open" />
  <TextBox> . . . </TextBox>
</StackPanel>
// Create the UI elements.
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";

// Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);

// Attach event handlers.
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);
' Create the UI elements.
Dim textInputStackPanel As New StackPanel()
Dim textInputeButton As New Button()
Dim textInputTextBox As New TextBox()
textInputeButton.Content = "Open"

' Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton)
textInputStackPanel.Children.Add(textInputTextBox)

' Attach event handlers.
AddHandler textInputStackPanel.KeyDown, AddressOf OnTextInputKeyDown
AddHandler textInputeButton.Click, AddressOf OnTextInputButtonClick

코드의 두 번째 세그먼트에는 이벤트 처리기가 포함되어 있습니다.

private void OnTextInputKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
    {
        handle();
        e.Handled = true;
    }
}

private void OnTextInputButtonClick(object sender, RoutedEventArgs e)
{
    handle();
    e.Handled = true;
}

public void handle()
{
    MessageBox.Show("Pretend this opens a file");
}
Private Sub OnTextInputKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
    If e.Key = Key.O AndAlso Keyboard.Modifiers = ModifierKeys.Control Then
        handle()
        e.Handled = True
    End If
End Sub

Private Sub OnTextInputButtonClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
    handle()
    e.Handled = True
End Sub

Public Sub handle()
    MessageBox.Show("Pretend this opens a file")
End Sub

입력 이벤트는 이벤트 경로를 버블링 하기 때문에에서 StackPanel 키보드 포커스가 있는 요소에 관계 없이 입력을 받습니다. 컨트롤에는 TextBox 먼저 알림이 표시 되 고가 OnTextInputKeyDown TextBox 입력을 처리 하지 않은 경우에만 처리기가 호출 됩니다. 이벤트 PreviewKeyDown 대신 이벤트를 사용 하는 경우 KeyDown OnTextInputKeyDown 처리기가 먼저 호출 됩니다.

이 예제에서 처리 논리는 Ctrl+O에 대해 한 번, 그리고 단추의 클릭 이벤트에 대해 한 번으로 총 두 번 작성되었습니다. 입력 이벤트를 직접 처리하는 대신 명령을 사용하면 이를 간편하게 처리할 수 있습니다. 명령에 대해서는 이 개요 항목과 명령 개요에서 설명합니다.

터치 및 조작

Windows 7 운영 체제의 새로운 하드웨어 및 API를 사용하면 애플리케이션이 여러 터치에서 동시에 입력을 수신할 수 있습니다. WPF를 사용하면 애플리케이션에서 터치가 발생할 때 이벤트를 발생시킴으로써 마우스나 키보드와 같은 다른 입력에 응답하는 것과 유사한 방식으로 터치를 감지하고 이에 응답할 수 있습니다.

WPF는 터치가 발생할 때 두 가지 형식의 이벤트, 즉 터치 이벤트와 조작 이벤트를 노출합니다. 터치 이벤트는 터치 스크린의 각 손가락과 그 이동에 대한 원시 데이터를 제공합니다. 조작 이벤트는 특정 작업으로 입력을 해석합니다. 이 섹션에서는 두 가지 형식의 이벤트에 대해 모두 설명합니다.

필수 구성 요소

터치에 응답하는 애플리케이션을 개발하려면 다음 구성 요소가 필요합니다.

  • Visual Studio 2010

  • Windows 7

  • Windows Touch를 지원하는 터치 스크린과 같은 디바이스

용어

터치에 대해 설명할 때 다음 용어가 사용됩니다.

  • 터치 는 Windows 7에서 인식되는 사용자 입력 형식입니다. 일반적으로 터치 스크린에 손가락을 대면 터치가 시작됩니다. 랩톱 컴퓨터에서 일반적으로 사용되는 터치 패드와 같은 디바이스는 디바이스가 손가락의 위치와 움직임을 마우스 입력으로 단순히 변환하는 경우 터치를 지원하지 않습니다.

  • 멀티 터치 는 둘 이상의 지점에서 동시에 발생하는 터치입니다. Windows 7 및 WPF에서 멀티 터치를 지원합니다. WPF에 대한 설명서에서 터치를 설명할 때마다 이 개념이 멀티 터치에 적용됩니다.

  • 터치가 개체에 적용 되는 물리적 작업으로 해석 되 면 조작이 발생 합니다. WPF에서 조작 이벤트는 입력을 변환, 확장 또는 회전 조작으로 해석합니다.

  • touch device는 터치 스크린에서 한 손가락과 같은 터치식 입력을 생성하는 디바이스를 나타냅니다.

터치에 반응하는 컨트롤

보기에서 스크롤된 콘텐츠가 있는 경우 컨트롤에서 손가락을 드래그하여 다음 컨트롤을 스크롤할 수 있습니다.

ScrollViewer 연결 된 속성을 정의 합니다 ScrollViewer.PanningMode .이 속성을 사용 하면 터치식 이동을 가로, 세로, 둘 다 또는 둘 다 사용 하지 않을 지 여부를 지정할 수 있습니다. ScrollViewer.PanningDeceleration속성은 사용자가 터치 스크린에서 손가락을 뗄 때 스크롤이 느려지는 속도를 지정 합니다. ScrollViewer.PanningRatio연결 된 속성은 조작 오프셋을 변환할 스크롤 오프셋의 비율을 지정 합니다.

터치 이벤트

기본 클래스,, UIElement UIElement3D 및는 ContentElement 응용 프로그램에서 터치에 응답할 수 있도록 구독할 수 있는 이벤트를 정의 합니다. 터치 이벤트는 애플리케이션이 터치를 개체 조작이 아닌 다른 것으로 해석할 때 유용합니다. 예를 들어 사용자가 하나 이상의 손가락으로 그릴 수 있는 애플리케이션은 터치 이벤트를 구독합니다.

세 클래스 모두 다음과 같은 이벤트를 정의합니다. 이 이벤트는 정의 클래스에 관계없이 유사하게 동작합니다.

키보드 및 마우스 이벤트와 마찬가지로 터치 이벤트는 라우트된 이벤트입니다. Preview로 시작하는 이벤트는 터널링 이벤트이고 Touch로 시작하는 이벤트는 버블링 이벤트입니다. 라우트된 이벤트에 대한 자세한 내용은 라우트된 이벤트 개요를 참조하세요. 이러한 이벤트를 처리 하는 경우 또는 메서드를 호출 하 여 모든 요소를 기준으로 하는 입력의 위치를 가져올 수 있습니다 GetTouchPoint GetIntermediateTouchPoints .

터치 이벤트 간의 상호 작용을 이해하려면 사용자가 한 손가락을 요소 위에 놓고 손가락을 요소에서 움직인 다음 요소에서 손가락을 들어 올리는 시나리오를 고려해 보세요. 다음 그림에서는 버블링 이벤트를 실행하는 것을 보여 줍니다(단순하게 하기 위해 터널링 이벤트는 생략됨).

터치 이벤트 시퀀스 터치 이벤트

다음 목록은 앞의 그림에서 이벤트 시퀀스를 설명합니다.

  1. TouchEnter 이벤트는 사용자가 요소에 손가락을 놓을 때 한 번 발생 합니다.

  2. TouchDown 이벤트는 한 번 발생 합니다.

  3. TouchMove사용자가 요소 내에서 손가락을 움직이면 이벤트가 여러 번 발생 합니다.

  4. TouchUp 이벤트는 사용자가 요소에서 손가락을 뗄 때 한 번 발생 합니다.

  5. TouchLeave 이벤트는 한 번 발생 합니다.

3개 이상의 손가락이 사용되면 각 손가락마다 이벤트가 발생합니다.

조작 이벤트

응용 프로그램에서 사용자가 개체를 조작할 수 있도록 하는 경우 UIElement 클래스는 조작 이벤트를 정의 합니다. 터치 위치를 단순히 보고하는 터치 이벤트와 달리 조작 이벤트는 입력을 해석할 수 있는 방법을 보고합니다. 변환, 확장 및 회전이라는 세 가지 형식의 조작이 있습니다. 다음 목록은 세 가지 형식의 조작을 호출하는 방법을 설명합니다.

  • 개체에 손가락을 대고 터치 스크린에서 손가락을 움직이면 변환 조작을 호출합니다. 그러면 일반적으로 개체를 이동합니다.

  • 개체 위에 두 개의 손가락을 놓고 손가락을 서로 더 가깝게 또는 멀리 움직여 확장 조작을 호출합니다. 그러면 일반적으로 개체의 크기를 조정합니다.

  • 개체에 두 손가락을 놓고 손가락을 서로 회전하면 회전 조작을 호출합니다. 그러면 일반적으로 개체를 회전합니다.

둘 이상의 조작 형식이 동시에 발생할 수 있습니다.

개체가 조작에 응답하게 하면 개체에 관성이 있는 것처럼 보일 수 있습니다. 그러면 개체가 실제 세계를 시뮬레이트하게 만들 수 있습니다. 예를 들어 테이블에서 책을 밀 때 충분히 세게 밀면 책을 놓은 후에도 책이 계속 움직입니다. WPF을 사용하면 사용자가 손가락을 개체에서 뗀 후 조작 이벤트를 발생시켜 이 동작을 시뮬레이트할 수 있습니다.

사용자가 개체를 이동, 크기 조정 및 회전할 수 있게 하는 애플리케이션을 만드는 방법에 대한 자세한 내용은 연습: 첫 번째 터치 애플리케이션 만들기를 참조하세요.

UIElement 다음과 같은 조작 이벤트를 정의 합니다.

기본적으로는 UIElement 이러한 조작 이벤트를 수신 하지 않습니다. 에서 조작 이벤트를 수신 하려면 UIElement UIElement.IsManipulationEnabled 를로 설정 true 합니다.

조작 이벤트 실행 경로

사용자가 개체를 “throw”하는 시나리오를 고려해 보겠습니다. 사용자가 개체 위에 손가락을 놓고 터치 스크린에서 짧은 거리만큼 손가락을 이동한 다음 개체가 움직이는 동안 손가락을 뗍니다. 그 결과 사용자가 손가락을 뗀 후에도 개체가 사용자의 손가락 아래에서 계속 움직입니다.

다음 그림에서는 조작 이벤트의 실행 경로 및 각 이벤트에 대한 중요한 정보를 보여 줍니다.

조작 이벤트 시퀀스 조작 이벤트

다음 목록은 앞의 그림에서 이벤트 시퀀스를 설명합니다.

  1. ManipulationStarting 이벤트는 사용자가 개체에 손가락을 놓을 때 발생 합니다. 무엇 보다도이 이벤트를 통해 속성을 설정할 수 있습니다 ManipulationContainer . 이후 이벤트에서 조작의 위치는에 상대적 ManipulationContainer 입니다. 이외의 이벤트에서 ManipulationStarting 이 속성은 읽기 전용 이므로 ManipulationStarting 이 속성을 설정할 수 있는 유일한 시간은 이벤트입니다.

  2. ManipulationStarted 이벤트는 다음에 발생 합니다. 이 이벤트는 조작의 출처를 보고합니다.

  3. ManipulationDelta이벤트는 사용자가 터치 스크린에서 손가락을 움직일 때 여러 번 발생 합니다. DeltaManipulation클래스의 속성은 ManipulationDeltaEventArgs 조작이 이동, 확장 또는 변환으로 해석 되는지 여부를 보고 합니다. 바로 여기서 개체 조작 작업의 대부분이 수행됩니다.

  4. ManipulationInertiaStarting 이벤트는 사용자의 손가락이 개체와의 연결이 끊어질 때 발생 합니다. 이 이벤트를 사용하면 관성이 발생하는 동안 수행되는 조작의 감속을 지정할 수 있습니다. 따라서 사용자가 선택한 여러 가지 실제 공간 또는 특성을 개체가 에뮬레이트할 수 있습니다. 예를 들어 애플리케이션에 실제 세계의 항목을 나타내는 개체가 두 개 있고 한 개체가 다른 개체보다 무거운 경우를 가정해 봅니다. 이 경우 무거운 개체가 가벼운 개체보다 더 빠르게 감속되도록 할 수 있습니다.

  5. ManipulationDelta 이벤트는 관성이 발생할 때 여러 번 발생 합니다. 이 이벤트는 사용자가 터치 스크린에서 손가락을 이동하고 WPF에서 관성을 시뮬레이트하는 경우에 발생합니다. 즉, ManipulationDelta 는 이벤트 전후에 발생 ManipulationInertiaStarting 합니다. ManipulationDeltaEventArgs.IsInertial속성은 관성 중에 이벤트가 발생 하는지 여부를 보고 ManipulationDelta 하므로 해당 속성을 확인 하 고 해당 값에 따라 다른 작업을 수행할 수 있습니다.

  6. ManipulationCompleted 이벤트는 조작과 모든 관성이 종료 될 때 발생 합니다. 즉, 모든 ManipulationDelta 이벤트가 발생 한 후 ManipulationCompleted 조작이 완료 되었음을 알리는 이벤트가 발생 합니다.

UIElement또한는 이벤트를 정의 합니다 ManipulationBoundaryFeedback . 이 이벤트는 ReportBoundaryFeedback 이벤트에서 메서드가 호출 될 때 발생 합니다 ManipulationDelta . ManipulationBoundaryFeedback이벤트를 사용 하면 개체가 경계에 도달할 때 응용 프로그램 또는 구성 요소가 시각적 피드백을 제공할 수 있습니다. 예를 들어, Window 클래스는 ManipulationBoundaryFeedback 해당 가장자리가 나타날 때 창이 약간 이동 되도록 이벤트를 처리 합니다.

Cancel이벤트를 제외한 모든 조작 이벤트의 이벤트 인수에서 메서드를 호출 하 여 조작을 취소할 수 있습니다 ManipulationBoundaryFeedback . 를 호출 하면 Cancel 조작 이벤트가 더 이상 발생 하지 않고 터치를 위해 마우스 이벤트가 발생 합니다. 다음 표에서는 조작이 취소되는 시점과 발생하는 마우스 이벤트 간의 관계에 대해 설명합니다.

Cancel이 호출되는 이벤트 이미 발생한 입력에 대해 발생하는 마우스 이벤트
ManipulationStartingManipulationStarted 마우스 누름 이벤트
ManipulationDelta 마우스 누름 및 마우스 이동 이벤트
ManipulationInertiaStartingManipulationCompleted 마우스 누름, 마우스 이동 및 마우스 놓기 이벤트

Cancel조작이 관성에 있을 때를 호출 하는 경우 메서드는을 반환 하 false 고 입력은 마우스 이벤트를 발생 시 키 지 않습니다.

터치 이벤트와 조작 이벤트의 관계

UIElement 항상 터치 이벤트를 받을 수 있습니다. IsManipulationEnabled속성이로 설정 된 경우 trueUIElement 터치 및 조작 이벤트를 모두 수신할 수 있습니다. TouchDown이벤트가 처리 되지 않은 경우 (즉, Handled 속성이 인 경우 false ) 조작 논리는 요소에 터치를 캡처하고 조작 이벤트를 생성 합니다. Handled이벤트에서 속성이로 설정 된 경우 true TouchDown 조작 논리는 조작 이벤트를 생성 하지 않습니다. 다음 그림에서는 터치 이벤트와 조작 이벤트의 관계를 보여 줍니다.

터치 이벤트와 조작 이벤트 간의 관계 터치 및 조작 이벤트

다음 목록에서는 앞의 그림에 나와 있는 터치 이벤트와 조작 이벤트의 관계에 대해 설명합니다.

포커스

WPF에는 포커스와 관련된 두 가지 주요 개념인 키보드 포커스와 논리 포커스가 있습니다.

키보드 포커스

키보드 포커스는 키보드 입력을 받고 있는 요소를 말합니다. 키보드 포커스가 있는 전체 데스크탑에는 요소가 하나뿐이어야 합니다. 에서 WPF 키보드 포커스가 있는 요소는 IsKeyboardFocused 을로 설정 true 합니다. 정적 Keyboard 메서드는 FocusedElement 현재 키보드 포커스가 있는 요소를 반환 합니다.

키보드 포커스는 요소로 탭 이동 하거나 등의 특정 요소에서 마우스를 클릭 하 여 가져올 수 있습니다 TextBox . 클래스의 메서드를 사용 하 여 프로그래밍 방식으로 키보드 포커스를 가져올 수도 있습니다 Focus Keyboard . Focus 지정 된 요소에 키보드 포커스를 지정 하려고 시도 합니다. 에서 반환 하는 요소는 Focus 현재 키보드 포커스가 있는 요소입니다.

요소가 키보드 포커스를 가져오도록 하려면 Focusable 속성 및 IsVisible 속성을 true 로 설정 해야 합니다. 등의 일부 클래스 Panel Focusable false 는 기본적으로로 설정 되어 있으므로 해당 요소에서 포커스를 얻을 수 있도록 하려면이 속성을로 설정 해야 할 수 있습니다 true .

다음 예제에서는를 사용 하 여에 Focus 키보드 포커스를 설정 Button 합니다. 응용 프로그램에서 초기 포커스를 설정 하는 데 권장 되는 위치가 Loaded 이벤트 처리기에 있습니다.

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}
Private Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
    ' Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton)
End Sub

키보드 포커스에 대한 자세한 내용은 포커스 개요를 참조하세요.

논리 포커스

논리적 포커스는 FocusManager.FocusedElement 포커스 범위에서을 참조 합니다. 애플리케이션에 논리 포커스가 있는 요소는 여러 개일 수 있지만, 특정 포커스 범위에 논리 포커스가 있는 요소는 하나뿐일 수 있습니다.

포커스 범위는 해당 범위 내에서를 추적 하는 컨테이너 요소입니다 FocusedElement . 포커스가 포커스 범위를 벗어나면 포커스가 있는 요소에서 키보드 포커스를 잃지만 논리 포커스는 유지합니다. 포커스가 포커스 범위로 돌아오면 포커스가 있는 요소가 키보드 포커스를 갖습니다. 이렇게 하면 여러 포커스 범위 사이에서 키보드 포커스가 변경되더라도 포커스 범위 내에서 포커스가 있는 요소는 포커스가 다시 돌아올 때 포커스가 있는 상태로 유지됩니다.

에서 XAML(Extensible Application Markup Language) FocusManager 연결 된 속성을로 설정 IsFocusScope true 하거나 메서드를 사용 하 여 연결 된 속성을 설정 하 여 코드에서 SetIsFocusScope 요소를 포커스 범위로 설정할 수 있습니다.

다음 예제에서는 연결 된 StackPanel 속성을 설정 하 여을 포커스 범위로 만듭니다 IsFocusScope .

<StackPanel Name="focusScope1" 
            FocusManager.IsFocusScope="True"
            Height="200" Width="200">
  <Button Name="button1" Height="50" Width="50"/>
  <Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)

기본적으로 포커스 범위에 해당 하는 클래스는 WPF Window ,, Menu ToolBarContextMenu 입니다.

키보드 포커스가 있는 요소에는 자신이 속한 포커스 범위에 대 한 논리 포커스가 있습니다. 따라서 클래스 또는 기본 요소 클래스의 메서드를 사용 하 여 요소에 포커스를 설정 하면 Focus Keyboard 요소에 키보드 포커스와 논리 포커스를 제공 하려고 합니다.

포커스 범위에서 포커스가 있는 요소를 확인 하려면를 사용 GetFocusedElement 합니다. 포커스 범위에 대 한 포커스가 있는 요소를 변경 하려면를 사용 SetFocusedElement 합니다.

논리 포커스에 대한 자세한 내용은 포커스 개요를 참조하세요.

마우스 위치

WPF입력 API는 좌표 공간에 관한 유용한 정보를 제공 합니다. 예를 들어 좌표 (0,0)은 좌표의 왼쪽 위를 나타냅니다. 그러나 트리에서 어떤 요소의 왼쪽 위인가요? 즉, 좌표가 나타내는 요소가 입력 대상인지 이벤트 처리기를 연결한 요소인지 또는 다른 요소인지 알 수 없습니다. 혼동을 피하기 위해 WPF 입력 API는 마우스를 통해 얻은 좌표를 사용할 때 참조 프레임을 지정 해야 합니다. GetPosition메서드는 지정 된 요소를 기준으로 마우스 포인터의 좌표를 반환 합니다.

마우스 캡처

마우스 디바이스에는 마우스 캡처라고 하는 모달 특성이 있습니다. 마우스 캡처는 끌어서 놓기 작업이 시작될 때 전환되는 입력 상태를 유지함으로써 마우스 포인터의 명목상 화면 위치와 관련된 다른 작업이 발생할 필요가 없도록 하기 위해 사용됩니다. 마우스를 끄는 동안 끌어서 놓기 작업을 중단하지 않고는 클릭할 수 없으므로 끌기 원점에서 마우스 캡처를 보유하는 동안에는 대부분의 마우스 이동 동작이 적절하지 않게 됩니다. 입력 시스템은 마우스 캡처 상태를 확인할 수 있는 Api 뿐만 아니라 특정 요소에 마우스 캡처를 적용 하거나 마우스 캡처 상태를 지울 수 있는 api를 노출 합니다. 끌어서 놓기 작업에 대한 자세한 내용은 끌어서 놓기 개요를 참조하세요.

명령

명령을 사용하면 디바이스 입력에 비해 보다 의미적 수준에서 입력을 처리할 수 있습니다. 명령은 Cut, Copy, Paste 또는 Open과 같은 단순한 지시문입니다. 명령은 명령 논리를 중앙 집중화하는 데 유용합니다. 동일한 명령은에서 Menu ToolBar 또는 바로 가기 키를 통해 액세스할 수 있습니다. 또한 명령은 명령을 사용할 수 없을 때 컨트롤을 비활성화하는 메커니즘도 제공합니다.

RoutedCommand 는 WPF 의 구현입니다 ICommand . RoutedCommand가 실행 되 면 PreviewExecutedExecuted 이벤트가 명령 대상에서 발생 하 고, 다른 입력과 마찬가지로 요소 트리를 통해 터널링 및 버블링 됩니다. 명령 대상이 설정되어 있지 않으면 키보드 포커스가 있는 요소가 명령 대상이 됩니다. 명령을 수행 하는 논리는에 연결 됩니다 CommandBinding . Executed CommandBinding 특정 명령에 대 한 이벤트가에 도달 하면의 ExecutedRoutedEventHandler CommandBinding 가 호출 됩니다. 이 처리기는 명령의 작업을 수행합니다.

명령에 대한 자세한 내용은 명령 개요를 참조하세요.

WPF 는,,, 및로 구성 된 일반적인 명령 라이브러리를 제공 하거나 사용자가 ApplicationCommands MediaCommands ComponentCommands NavigationCommands EditingCommands 직접 정의할 수 있습니다.

다음 예제에서는를 MenuItem 클릭 하면에서 Paste 키보드 포커스가 있는 것으로 가정 하 여에 대 한 명령을 호출 하도록를 설정 하는 방법을 보여 줍니다 TextBox TextBox .

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste" />
  </Menu>
  <TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As New MenuItem()

' Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem)
mainStackPanel.Children.Add(stackPanelMenu)
mainStackPanel.Children.Add(pasteTextBox)

' Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste

WPF에서 명령에 대한 자세한 내용은 명령 개요를 참조하세요.

입력 시스템 및 기본 요소

, 및 클래스에 의해 정의 된 연결 된 이벤트와 같은 입력 이벤트는 Mouse Keyboard Stylus 입력 시스템에서 발생 하 고 런타임에 시각적 트리의 적중 테스트를 기반으로 개체 모델의 특정 위치에 삽입 됩니다.

, 및가 연결 된 이벤트로 정의 하는 각 이벤트는 Mouse Keyboard Stylus 기본 요소 클래스 UIElementContentElement 새로운 라우트된 이벤트로도 다시 노출 됩니다. 기본 요소의 라우트된 이벤트는 원래 연결된 이벤트를 처리하고 이벤트 데이터를 다시 사용하는 클래스를 통해 생성됩니다.

입력 이벤트가 해당 기본 요소 입력 이벤트 구현을 통해 특정 소스 요소와 연결되는 경우 이 입력 이벤트는 논리적 트리 개체 및 시각적 트리 개체의 조합을 기반으로 하는 이벤트 경로의 나머지 부분을 통해 전송할 수 있으며 애플리케이션 코드에서 처리할 수 있습니다. 일반적으로 및 UIElement ContentElement 코드에서 보다 직관적인 이벤트 처리기 구문을 사용할 수 있기 때문에 및에서 라우트된 이벤트를 사용 하 여 이러한 장치 관련 입력 이벤트를 처리 하는 것이 더 편리 XAML 합니다. 대신 프로세스를 시작한 연결된 이벤트를 처리할 수도 있지만 이 경우 몇 가지 문제에 직면할 수 있습니다. 예를 들어 기본 요소 클래스 처리를 통해 연결된 이벤트가 처리된 것으로 표시될 수 있습니다. 또한 연결된 이벤트에 대한 처리기를 연결하기 위해 실제 이벤트 구문 대신 접근자 메서드를 사용해야 합니다.

다음 단계

이제 보다 다양한 기술로 WPF에서 입력을 처리할 수 있게 되었습니다. 따라서 WPF에서 사용하는 라우트된 이벤트 메커니즘 및 다양한 형식의 입력 이벤트에 대해 보다 잘 이해하고 있어야 합니다.

WPF 프레임워크 요소 및 이벤트 라우팅에 대해 보다 자세히 설명하는 추가 리소스가 있습니다. 자세한 내용은 명령 개요, 포커스 개요, 기본 요소 개요,WPF의 트리라우트된 이벤트 개요와 같은 개요를 참조하세요.

참고 항목