연결된 이벤트 개요

Extensible Application Markup Language (XAML)은 연결된 이벤트라고 하는 이벤트의 형식과 언어 구성 요소를 정의합니다. 연결된 이벤트 개념을 사용하면 실제로 이벤트를 정의하거나 상속하는 요소가 아닌 임의의 요소에 특정 이벤트에 대한 처리기를 추가할 수 있습니다. 이 경우 이벤트를 발생시키는 개체나 인스턴스를 처리하는 대상 모두 이벤트를 정의하거나 다른 방식으로 "소유"하지 않습니다.

이 항목에는 다음 단원이 포함되어 있습니다.

  • 사전 요구 사항
  • 연결된 이벤트 구문
  • WPF에서 연결된 이벤트를 구현하는 방법
  • 연결된 이벤트 시나리오
  • WPF에서 연결된 이벤트 처리
  • 고유한 연결된 이벤트를 라우트된 이벤트로 정의
  • WPF 연결된 이벤트 발생시키기
  • 관련 항목

사전 요구 사항

이 항목에서는 라우트된 이벤트 개요XAML 개요(WPF)를 학습한 것으로 간주합니다.

연결된 이벤트 구문

연결된 이벤트에는 연결된 이벤트 사용을 지원하기 위해 백업 코드에서 사용해야 하는 XAML 구문과 코딩 패턴이 있습니다.

XAML 구문에서는 연결된 이벤트를 이벤트 이름만으로 지정하는 것이 아니라 소유 형식과 이벤트 이름을 점(.)으로 구분하여 지정합니다. 이벤트 이름은 소유 형식의 이름으로 한정되므로 연결된 이벤트 구문을 사용하면 모든 연결된 이벤트를 인스턴스화할 수 있는 모든 요소에 연결할 수 있습니다.

예를 들어 다음은 사용자 지정 NeedsCleaning 연결된 이벤트에 대한 처리기를 연결하는 XAML 구문입니다.

<aqua:Aquarium Name="theAquarium" Height="600" Width="800" aqua:AquariumFilter.NeedsCleaning="WashMe"/>

aqua: 접두사에 주의하십시오. 이 경우에는 연결된 이벤트가 매핑된 사용자 지정 xmlns에서 오는 사용자 지정 이벤트이므로 이 접두사가 필요합니다.

WPF에서 연결된 이벤트를 구현하는 방법

WPF에서 연결된 이벤트는 RoutedEvent 필드를 기반으로 하며 발생된 후에 트리를 통해 라우트됩니다. 일반적으로 연결된 이벤트의 소스(이벤트를 발생시킨 개체)는 시스템 또는 서비스 소스이므로, 이벤트를 발생시킨 코드를 실행하는 개체는 요소 트리에 직접 포함되지 않습니다.

연결된 이벤트 시나리오

WPF에서는 연결된 이벤트가 정적 Mouse 클래스 또는 Validation 클래스를 통해 활성화되는 이벤트와 같이 서비스 수준 추상화가 있는 특정 기능 영역에 존재합니다. 서비스와 상호 작용하거나 서비스를 사용하는 클래스는 연결된 이벤트 구문의 이벤트를 사용하거나 클래스를 서비스 기능에 통합하는 방식과 관련된 라우트 이벤트로 연결된 이벤트를 노출할 수 있습니다.

WPF에서는 다양한 연결된 이벤트가 정의되지만 연결된 이벤트를 직접 사용하거나 처리하는 경우는 매우 드뭅니다. 일반적으로 연결된 이벤트는 아키텍처 용도로 사용되지만, 그 후 CLR 이벤트 "래퍼"를 기반으로 하여 연결되지 않는 라우트된 이벤트로 전달됩니다.

예를 들어 XAML 또는 코드에서 연결된 이벤트 구문을 처리하는 대신, UIElementMouseDown을 사용하면 해당 UIElement에서 기본 연결된 이벤트 Mouse.MouseDown을 보다 쉽게 처리할 수 있습니다. 연결된 이벤트를 사용하면 장래에 입력 장치를 확장할 수 있으므로 아키텍처 용도로 사용할 수 있습니다. 가상 장치에서는 마우스 입력을 시뮬레이션하기 위해 Mouse.MouseDown을 발생시키기만 하면 됩니다. 이를 위해 Mouse에서 파생시킬 필요가 없습니다. 하지만 이 시나리오에는 이벤트를 처리하는 코드가 필요하며 연결된 이벤트의 XAML 처리는 이 시나리오와 관련이 없습니다.

WPF에서 연결된 이벤트 처리

연결된 이벤트를 처리하는 프로세스와 사용자가 작성할 처리기 코드는 기본적으로 라우트된 이벤트의 경우와 동일합니다.

일반적으로 WPF 연결된 이벤트는 WPF 라우트된 이벤트와 크게 다르지 않습니다. 두 이벤트의 차이점은 이벤트가 발생하는 방식과 클래스에서 멤버로 노출되는 방식입니다. 특히 클래스에서 멤버로 노출되는 방식은 XAML 처리기 구문에도 영향을 미칩니다.

하지만 앞서 설명한 것처럼 기존의 WPF 연결된 이벤트는 특별히 WPF 처리에 사용하기 위한 것은 아닙니다. 그보다는 합성 과정에서 합성 요소를 통해 부모 요소에 상태를 보고하는 것이 이 이벤트의 용도인데, 이 경우 이벤트는 주로 코드로 발생하고 관련 부모 클래스의 클래스 처리에 의존합니다. 예를 들어 Selector 내의 항목은 연결된 Selected 이벤트를 발생시킵니다. 그러면 이 이벤트는 Selector 클래스로 처리되는 클래스가 되고 그 후 Selector 클래스에 의해 다른 라우트된 이벤트인 SelectionChanged로 변환됩니다. 라우트된 이벤트와 클래스 처리에 대한 자세한 내용은 라우트된 이벤트를 처리된 것으로 표시 및 클래스 처리를 참조하십시오.

고유한 연결된 이벤트를 라우트된 이벤트로 정의

공용 WPF 기본 클래스에서 파생시키는 경우 클래스에 특정 패턴 메서드를 포함시키고 기본 클래스에 이미 있는 유틸리티 메서드를 사용하여 고유한 연결된 이벤트를 구현할 수 있습니다.

패턴은 다음과 같습니다.

  • 매개 변수 두 개가 있는 Add*Handler 메서드. 첫 번째 매개 변수는 이벤트를 식별해야 하며 식별된 이벤트는 메서드 이름에서 * 기호가 있는 이름과 일치해야 합니다. 두 번째 매개 변수는 추가할 처리기입니다. 이 메서드는 반환 값이 없는 공개 및 정적 메서드여야 합니다.

  • 매개 변수 두 개가 있는 Remove*Handler 메서드. 첫 번째 매개 변수는 이벤트를 식별해야 하며 식별된 이벤트는 메서드 이름에서 * 기호가 있는 이름과 일치해야 합니다. 두 번째 매개 변수는 제거할 처리기입니다. 이 메서드는 반환 값이 없는 공개 및 정적 메서드여야 합니다.

연결된 이벤트 처리기 특성이 요소에 선언될 경우 Add*Handler 접근자 메서드를 사용하면 XAML을 빠르게 처리할 수 있습니다. 또한 Add*Handler 및 Remove*Handler 메서드를 사용하면 코드를 통해 이벤트 처리기 저장소에 액세스하여 연결된 이벤트를 이용할 수 있습니다.

이 일반 패턴은 지정된 XAML 판독기를 구현할 때 지원 언어 및 아키텍처에서 기반 이벤트를 식별하는 데 서로 다른 스키마를 사용할 수 있기 때문에 아직 프레임워크에 실질적으로 구현할 정도로 정밀하지는 않습니다. 이것이 WPF에서 연결된 이벤트를 라우트된 이벤트로 구현하는 이유 중 하나입니다. 이벤트(RoutedEvent)에 사용할 식별자는 WPF 이벤트 시스템에 이미 정의되어 있습니다. 또한 이벤트 라우팅은 연결된 이벤트의 XAML 언어 수준 개념에서 자연스러운 구현 확장입니다.

WPF 연결된 이벤트에 Add*Handler를 구현하는 과정에서는 라우트된 이벤트와 처리기를 인수로 사용하는 AddHandler를 호출합니다.

이 구현 전략과 라우트된 이벤트 시스템은 일반적으로 연결된 이벤트의 처리를 UIElement 파생 클래스나 ContentElement 파생 클래스로 제한합니다. 이는 이러한 클래스에만 AddHandler가 구현되어 있기 때문입니다.

예를 들어 다음 코드에서는 연결된 이벤트를 라운트된 이벤트로 선언하는 WPF 연결된 이벤트 전략을 사용하여 소유자 클래스 Aquarium에서 NeedsCleaning 연결된 이벤트를 정의합니다.

Public Shared ReadOnly NeedsCleaningEvent As RoutedEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))
Public Shared Sub AddNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub
Public Shared Sub RemoveNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub
public static readonly RoutedEvent NeedsCleaningEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));
public static void AddNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
public static void RemoveNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}

실제로, 연결된 이벤트 식별자 필드를 설정하는 데 사용되는 메서드인 RegisterRoutedEvent는 연결되지 않은 라우트된 이벤트를 등록하는 데 사용되는 메서드와 동일한 메서드입니다. 연결된 이벤트와 라우트된 이벤트는 모두 중앙의 내부 저장소에 등록됩니다. 이 이벤트 저장소를 구현하면 라우트된 이벤트 개요에서 설명하는 "인터페이스 역할을 하는 이벤트"를 개념적으로 고려해 볼 수 있습니다.

WPF 연결된 이벤트 발생시키기

일반적인 경우에는 코드에서 WPF에 정의된 기존의 연결된 이벤트를 발생시킬 필요가 없습니다. 이러한 이벤트는 일반 "서비스" 개념 모델을 따르며 InputManager와 같은 서비스 클래스가 이벤트를 발생시키는 역할을 합니다.

하지만 RoutedEvent에 있는 연결된 이벤트를 기반으로 하는 WPF 모델에 기반한 사용자 지정 연결된 이벤트를 정의하는 경우 RaiseEvent를 사용하여 모든 UIElement 또는 ContentElement에서 연결된 이벤트를 발생시킬 수 있습니다. 연결된 이벤트 또는 연결되지 않은 이벤트를 모두 포함하여 라우트된 이벤트를 발생시키려면 요소 트리에서 특정 요소를 이벤트 소스로 선언해야 합니다. 이러한 소스는 RaiseEvent 호출자로 보고됩니다. 트리에서 어떤 요소가 소스로 보고되는지는 서비스에 따라 다릅니다.

참고 항목

개념

라우트된 이벤트 개요

XAML 구문 정보

WPF에 대한 XAML 및 사용자 지정 클래스