728x90
반응형

WPF - Routed Events
UI 요소들이 계층 구조(Visual Tree / Logical Tree)로 구성되어 있기 때문에, 이벤트가 부모 또는 자식 컨트롤까지 전달될 수 있는 기능이 필요하게 된다.
이러한 이벤트 전달 메커니즘을 Routed Event (라우트 이벤트) 라고 한다.
Routed Event의 종류 (이벤트 방향성)
1. Bubbling Event (버블링 이벤트)
- 자식 → 부모 방향으로 전달됨.
- 가장 일반적이며, 대부분의 컨트롤 이벤트가 이 타입.
- 예: Button.Click, TextBox.TextChanged
2. Tunneling Event
- 부모 → 자식 방향으로 전달됨.
- 이름에 Preview가 붙음.
- 예: PreviewMouseDown, PreviewKeyDown
3. Direct Event
- 일반적인 C# 이벤트처럼 한 객체에서만 발생.
- 예: Loaded, Initialized
public class MyControl : Control
{
// 1. RoutedEvent 등록
public static readonly RoutedEvent MyClickEvent =
EventManager.RegisterRoutedEvent(
"MyClick",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(MyControl));
// 2. .NET-style wrapper 정의
public event RoutedEventHandler MyClick
{
add { AddHandler(MyClickEvent, value); }
remove { RemoveHandler(MyClickEvent, value); }
}
// 3. 이벤트 발생 메서드
protected void RaiseMyClickEvent()
{
RoutedEventArgs args = new RoutedEventArgs(MyClickEvent);
RaiseEvent(args);
}
}
Route Event 핸들링
1. xaml에서 핸들링
<Button Click="Button_Click" />
2. 코드에서 핸들러 등록
button.AddHandler(Button.ClickEvent, new RoutedEventHandler(Button_Click));
핸들러 안에서 라우팅 중단하고자 할때
private void Button_Click(object sender, RoutedEventArgs e)
{
e.Handled = true; // 이벤트 라우팅을 여기서 중단!
}
- AddHandler(..., handledEventsToo: true)로 e.Handled = true인 이벤트도 잡을 수 있음.
ex) 마우스 이벤트 (터널링 + 버블링)
실제 발생 순서
Grid_PreviewMouseDown → Button_PreviewMouseDown → Button_MouseDown → Grid_MouseDown
<Grid PreviewMouseDown="Grid_PreviewMouseDown"
MouseDown="Grid_MouseDown">
<Button Content="Click Me"
PreviewMouseDown="Button_PreviewMouseDown"
MouseDown="Button_MouseDown"/>
</Grid>
이벤트 체계 정리
1. Object Lifetime Events
- 컨트롤이나 요소가 생성되고 로드되는 시점에 발생하는 이벤트들.
- Initialized는 XAML에서 객체 초기화 시에만 발생하고, Loaded는 실제 렌더링 준비 완료 시점에 발생해요
| 이벤트 이름 | 설명 |
| Initialized | 객체가 생성되고 XAML 파싱이 완료되었을 때 발생 (생성자 이후) |
| Loaded | 요소가 논리 트리/비주얼 트리에 붙었을 때 발생 |
| Unloaded | 요소가 트리에서 분리될 때 발생 |
| DataContextChanged | 바인딩된 DataContext가 변경되었을 때 발생 |
2. Input Events
마우스, 키보드, 터치 등의 사용자 입력을 처리하는 이벤트
Preview 이벤트는 항상 터널링 방식으로 부모에서 자식 방향으로 먼저 호출된다
| MouseDown / PreviewMouseDown | Bubble / Tunnel | 마우스 버튼을 누를 때 |
| MouseUp / PreviewMouseUp | Bubble / Tunnel | 마우스 버튼을 뗄 때 |
| MouseMove / PreviewMouseMove | Bubble / Tunnel | 마우스를 움직일 때 |
| MouseEnter / MouseLeave | Direct | 요소에 마우스가 들어오거나 나갈 때 |
| MouseWheel | Bubble | 마우스 휠 스크롤 |
| MouseDoubleClick | Bubble | 더블 클릭 (ButtonBase 계열에서만 지원) |
| 이벤트 이름 | 라우팅 | 설명 |
| KeyDown / PreviewKeyDown | Bubble / Tunnel | 키 누름 |
| KeyUp / PreviewKeyUp | Bubble / Tunnel | 키 뗌 |
| TextInput | Bubble | 문자 입력이 완료될 때 (IME 포함) |
3. Focus Events
| 이벤트 이름 | 설명 |
| GotFocus / LostFocus | 포커스가 얻어졌거나 잃었을 때 |
| IsKeyboardFocusedChanged | 포커스 상태가 변경될 때 (이벤트가 아닌 프로퍼티 변경 감지) |
4. Layout Events
| 이벤트 이름 | 설명 |
| SizeChanged | 요소의 크기가 변경될 때 |
| LayoutUpdated | 모든 레이아웃 연산이 끝날 때 (자주 발생, 무겁게 쓰면 안됨) |
5. Binding/Property Change Events
- DependencyPropertyDescriptor.AddValueChanged(...) → Dependency Property 변경 감지용
- INotifyPropertyChanged → 일반 클래스에서 바인딩된 속성의 값이 바뀌었을 때
추가 내용
- MouseEnter, MouseLeave는 Direct Event라서 라우팅되지 않음.
- 모든 Preview 이벤트는 중간에서 차단(e.Handled = true) 가능.
- UI 구성할 때는 Loaded에서 초기화 작업을 하는 게 일반적.
'프로그래밍&IT > C# (Winfrom, WPF)' 카테고리의 다른 글
| [WPF] The Application (1) | 2025.08.04 |
|---|---|
| [WPF] Controls (3) | 2025.08.04 |
| [WPF] WPF의 기본 레이아웃 (Layout) (4) | 2025.08.03 |
| [Effective C#] Ch6. 그 외 것들 (2) safe code, CLS 규격 코드 작성하기, (0) | 2025.07.15 |
| [Effective C#] Ch6. 그 외 것들 (1) 박싱 & 언박싱 주의 , exception class, 강력한 예외 보장 (2) | 2025.07.15 |