연결된 이벤트 개요(WPF .NET)

XAML(Extensible Application Markup Language)은 연결된 이벤트라는 언어 구성 요소 및 이벤트 유형을 정의합니다. 연결된 이벤트는 비 요소 클래스에서 새 라우트된 이벤트를 정의하고 트리의 모든 요소에서 해당 이벤트를 발생시키는 데 사용할 수 있습니다. 이렇게 하려면 연결된 이벤트를 라우트된 이벤트로 등록하고 연결된 이벤트 기능을 지원하는 특정 지원 코드를 제공해야 합니다. 연결된 이벤트는 라우트된 이벤트로 등록되므로 요소에서 발생하는 경우 요소 트리를 통해 전파됩니다.

중요

.NET 7 및 .NET 6에 관한 데스크톱 가이드 설명서는 제작 중입니다.

필수 구성 요소

이 문서에서는 WPF(Windows Presentation Foundation) 라우트된 이벤트에 대한 기본 지식과 WPF에서 라우트된 이벤트 개요XAML을 읽었다고 가정합니다. XAML에 익숙하고 WPF 애플리케이션을 작성하는 방법을 알고 있으면 이 문서의 예제를 따라 하는 데 도움이 됩니다.

연결된 이벤트 구문

XAML 구문에서 연결된 이벤트는 이벤트 이름 소유자 형식으로 <owner type>.<event name> 지정됩니다. 이벤트 이름이 소유자 형식의 이름으로 정규화되기 때문에, 구문을 사용하여 인스턴스화할 수 있는 모든 요소에 이벤트를 연결할 수 있습니다. 이 구문은 이벤트 경로를 따라 임의 요소에 연결하는 일반 라우트된 이벤트의 처리기에도 적용됩니다.

다음 XAML 특성 구문은 AquariumFilter.Clean 연결된 이벤트에 대한 AquariumFilter_Clean 처리기를 aquarium1 요소에 연결합니다.

<aqua:Aquarium x:Name="aquarium1" Height="300" Width="400" aqua:AquariumFilter.Clean="AquariumFilter_Clean"/>

이 예제에서는 AquariumFilterAquarium 클래스가 다른 CLR(공용 언어 런타임) 네임스페이스 및 어셈블리에 있기 때문에 aqua: 접두사가 필요합니다.

코드 숨김에서 연결된 이벤트에 대한 처리기를 연결할 수도 있습니다. 이렇게 하려면 처리기가 연결해야 하는 개체에서 AddHandler 메서드를 호출하고 이벤트 식별자 및 처리기를 메서드에 매개 변수로 전달합니다.

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

WPF 연결된 이벤트는 RoutedEvent 필드에서 백업되는 라우트된 이벤트로 구현됩니다. 결과적으로 연결된 이벤트는 발생한 후 요소 트리를 통해 전파됩니다. 일반적으로 이벤트 원본이라고 하는 연결된 이벤트를 발생시키는 개체는 시스템 또는 서비스 원본입니다. 시스템 또는 서비스 원본은 요소 트리의 직접적인 부분이 아닙니다. 연결된 다른 이벤트의 경우 이벤트 원본은 복합 컨트롤 내의 구성 요소와 같은 트리의 요소일 수 있습니다.

연결된 이벤트 시나리오

WPF에서 연결된 이벤트는 서비스 수준 추상화가 있는 특정 기능 영역에서 사용됩니다. 예를 들어 WPF는 정적 Mouse 또는 Validation 클래스에서 사용하도록 설정된 연결된 이벤트를 사용합니다. 서비스와 상호 작용하거나 서비스를 사용하는 클래스는 연결된 이벤트 구문을 사용하여 이벤트와 상호 작용하거나 연결된 이벤트를 라우트된 이벤트로 표시할 수 있습니다. 후자의 옵션은 클래스가 서비스의 기능을 통합하는 방법의 일부입니다.

WPF 입력 시스템은 연결된 이벤트를 광범위하게 사용합니다. 그러나 거의 모든 연결된 이벤트는 기본 요소를 통해 연결되지 않은 동일한 라우트된 이벤트로 표시됩니다. 라우트된 각 입력 이벤트는 기본 요소 클래스의 멤버이며 CLR 이벤트 "래퍼"로 백업됩니다. 연결된 이벤트를 직접 사용하거나 처리하는 경우는 거의 없습니다. 인스턴스의 경우 XAML 또는 코드 숨김에서 연결된 이벤트 구문을 사용하는 것보다 동일한 UIElement.MouseDown 라우트된 이벤트를 통해 UIElement에서 기본 연결된 Mouse.MouseDown 이벤트를 처리하는 것이 더 쉽습니다.

연결된 이벤트는 나중에 입력 디바이스를 확장할 수 있도록 하여 아키텍처 용도로 사용됩니다. 예를 들어 새 입력 디바이스는 마우스 입력을 시뮬레이션하기 위해 Mouse.MouseDown을(를) 발생시켜야 하며, 이를 위해 Mouse에서 파생할 필요가 없습니다. 연결된 이벤트의 XAML 처리는 관련이 없으므로 이 시나리오에는 이벤트의 코드 처리가 포함됩니다.

연결된 이벤트 처리

연결된 이벤트를 코딩하고 처리하는 프로세스는 기본적으로 연결되지 않은 라우트된 이벤트의 경우와 동일합니다.

앞에서 설명한 것처럼 기존 WPF 연결된 이벤트는 일반적으로 WPF에서 직접 처리되지 않습니다. 연결된 이벤트의 목적은 복합 컨트롤 내의 요소가 해당 상태를 컨트롤 내의 부모 요소에 보고할 수 있도록 하는 것입니다. 이 시나리오에서 이벤트는 코드에서 발생하며 관련 부모 클래스의 클래스 처리에 의존합니다. 예를 들어 Selector 내의 항목은 Selected 연결된 이벤트를 발생시킨 다음, 클래스가 Selector 클래스에서 처리됩니다. Selector 클래스는 잠재적으로 Selected 이벤트를 SelectionChanged 라우트된 이벤트로 변환합니다. 라우트된 이벤트 및 클래스 처리에 대한 자세한 내용은 라우트된 이벤트를 처리된 것으로 표시 및 클래스 처리를 참조하십시오.

사용자 지정 연결된 이벤트 정의

일반적인 WPF 기본 클래스에서 파생되는 경우 클래스에 두 개의 접근자 메서드를 포함하여 사용자 지정 연결된 이벤트를 구현할 수 있습니다. 이러한 메서드는 다음과 같습니다.

  • 이벤트 처리기가 연결된 요소인 첫 번째 매개 변수와 추가할 이벤트 처리기의 두 번째 매개 변수가 있는 추가< 이벤트 이름>처리기 메서드입니다. 메서드는 반환 값이 없는 publicstatic이어야 합니다. 메서드는 AddHandler 기본 클래스 메서드를 호출하여 라우트된 이벤트 및 처리기를 인수로 전달합니다. 이 메서드는 요소에 이벤트 처리기를 연결하기 위한 XAML 특성 구문을 지원합니다. 이 메서드도 연결된 이벤트에 대한 이벤트 처리기 저장소에 대한 코드 액세스를 사용합니다.

  • 이벤트 처리기가 연결된 요소인 첫 번째 매개 변수와 제거할 이벤트 처리기의 두 번째 매개 변수가 있는 제거<이벤트 이름>처리기 메서드입니다. 메서드는 반환 값이 없는 publicstatic이어야 합니다. 메서드는 RemoveHandler 기본 클래스 메서드를 호출하여 라우트된 이벤트 및 처리기를 인수로 전달합니다. 이 메서드는 연결된 이벤트에 대한 이벤트 처리기 저장소에 대한 코드 액세스를 사용합니다.

RoutedEvent에 대한 식별자가 WPF 이벤트 시스템에 의해 정의되므로 WPF는 연결된 이벤트를 라우트된 이벤트로 구현합니다. 또한 이벤트 라우팅은 연결된 이벤트의 XAML 언어 수준 개념에 대한 자연스러운 확장입니다. 이 구현 전략은 연결된 이벤트에 대한 처리를 UIElement 파생 클래스 또는 ContentElement 파생 클래스로 제한합니다. 이러한 클래스에만 AddHandler 구현이 있기 때문입니다.

예를 들어 다음 코드는 요소 클래스가 아닌 AquariumFilter 소유자 클래스에 Clean 연결된 이벤트를 정의합니다. 이 코드는 연결된 이벤트를 라우트된 이벤트로 정의하고 필요한 접근자 메서드를 구현합니다.

public class AquariumFilter
{
    // Register a custom routed event using the bubble routing strategy.
    public static readonly RoutedEvent CleanEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));

    // Provide an add handler accessor method for the Clean event.
    public static void AddCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.AddHandler(CleanEvent, handler);
    }

    // Provide a remove handler accessor method for the Clean event.
    public static void RemoveCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.RemoveHandler(CleanEvent, handler);
    }
}
Public Class AquariumFilter

    ' Register a custom routed event using the bubble routing strategy.
    Public Shared ReadOnly CleanEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))

    ' Provide an add handler accessor method for the Clean event.
    Public Shared Sub AddCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[AddHandler](CleanEvent, handler)
        End If
    End Sub

    ' Provide a remove handler accessor method for the Clean event.
    Public Shared Sub RemoveCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[RemoveHandler](CleanEvent, handler)
        End If
    End Sub

End Class

연결된 이벤트 식별자를 반환하는 RegisterRoutedEvent 메서드는 연결되지 않은 라우트된 이벤트를 등록하는 데 사용되는 메서드와 동일합니다. 연결된/연결되지 않은 라우트된 이벤트 모두 중앙 집중화된 내부 저장소에 등록됩니다. 이 이벤트 저장소 구현은 라우트된 이벤트 개요에서 설명하는 “인터페이스로서의 이벤트”를 사용합니다.

연결되지 않은 라우트된 이벤트를 백업하는 데 사용되는 CLR 이벤트 "래퍼"와 달리 연결된 이벤트 접근자 메서드는 UIElement 또는 ContentElement에서 파생되지 않는 클래스에서 구현할 수 있습니다. 연결된 이벤트 지원 코드는 UIElement 인스턴스로 전달된 UIElement.AddHandlerUIElement.RemoveHandler 메서드를 호출하기 때문에 가능합니다. 반면, 연결하지 않은 라우트된 이벤트에 대한 CLR 래퍼는 해당 메서드를 소유 클래스에서 직접 호출하므로 클래스는 UIElement에서 파생되어야 합니다.

WPF 연결된 이벤트 발생

연결된 이벤트를 발생시키는 프로세스는 기본적으로 연결되지 않은 라우트된 이벤트의 경우와 동일합니다.

일반적으로 코드는 이러한 이벤트가 일반적인 "서비스" 개념적 모델을 따르기 때문에 기존 WPF 정의 연결된 이벤트를 발생시키지 않아도 됩니다. 해당 모델에서 InputManager과(와) 같은 서비스 클래스는 WPF 정의 연결된 이벤트를 발생시키는 역할을 합니다.

연결된 이벤트를 라우트된 이벤트에 기반한 WPF 모델을 사용하여 사용자 지정 연결 이벤트를 정의하는 경우 UIElement.RaiseEvent 메서드를 사용하여 UIElement 또는 ContentElement에 연결된 이벤트를 발생시킵니다. 라우트된 이벤트를 발생시킬 때 연결된 이벤트인지 여부에 관계없이 요소 트리의 요소를 이벤트 원본으로 지정해야 합니다. 그런 다음 해당 원본이 RaiseEvent 호출자로 보고됩니다. 예를 들어 aquarium1에서 AquariumFilter.Clean 연결된 라우트된 이벤트를 발생시킵니다.

aquarium1.RaiseEvent(new RoutedEventArgs(AquariumFilter.CleanEvent));
aquarium1.[RaiseEvent](New RoutedEventArgs(AquariumFilter.CleanEvent))

앞의 예제에서 aquarium1은(는) 이벤트 원본입니다.

추가 정보