본문 바로가기

프로그래밍&IT/C#.WPF

Winform (윈폼)의 컨트롤 이벤트와 WPF의 Routed event간의 차이 / RoutedEventArgs에서 많이 사용되는 내용

내가 거의 C# Winform(윈폼)으로만 먹고살다보니,

WPF의 기본 개념이 어렵다.

 

목차

  • Winform 컨트롤 이벤트와 WPF의 Routed event간의 차이
  • RoutedEventArgs에서 많이 사용되는 프로퍼티와 내용

 

Winform 컨트롤 이벤트와 WPF의 Routed event간의 차이

1. 이벤트 모델 비교

WinForm의 컨트롤 이벤트

  • WinForm은 일반적인 .NET 이벤트 모델을 사용합니다.
  • 각 컨트롤에 이벤트가 있으며, 이벤트가 발생하면 컨트롤 자체에서 직접 처리됩니다.
  • 이벤트의 버블링이나 터널링은 지원하지 않으며, 이벤트는 한 번 발생하면 해당 컨트롤에만 영향을 미칩니다.
  • 이벤트 핸들러는 이벤트가 발생한 컨트롤에 바로 연결됩니다.

WPF의 Routed Event

  • WPF는 RoutedEvent 모델을 사용합니다.
  • 이벤트가 한 컨트롤에서 발생하면 터널링(Tunneling)과 버블링(Bubbling)을 통해 부모 및 자식 컨트롤을 따라 이동할 수 있습니다.
  • Tunneling: 이벤트가 루트부터 시작해서 자식 컨트롤로 전달 (Preview 접두어 사용).
  • Bubbling: 이벤트가 자식 컨트롤에서 시작해 루트로 전달.
  • Routed Event의 핸들링은 특정 컨트롤뿐만 아니라 부모 컨트롤에서도 처리할 수 있어, 더욱 유연한 이벤트 처리가 가능합니다.
  • WPF의 이벤트는 RoutedEventArgs를 통해 전달되며, 이를 통해 이벤트 흐름을 제어하거나 취소할 수 있습니다.

2. 이벤트 흐름 차이 (Tunneling/Bubbling)

  • WinForm: 이벤트는 특정 컨트롤에서 시작되고 해당 컨트롤에서만 종료됩니다. 이벤트가 부모나 자식 컨트롤로 전달되지 않습니다.
  • WPF: 하나의 이벤트가 발생하면, 이 이벤트는 UI 트리를 통해 상위 및 하위 요소들로 이동할 수 있습니다.

3. WPF의 Routed Event 종류

  • Direct: WinForm과 유사하게 이벤트가 발생한 컨트롤에서만 처리.
  • Bubbling: 이벤트가 자식에서 부모로 전파.
  • Tunneling: 이벤트가 부모에서 자식으로 전파 (Preview 접두어 사용).

4. 이벤트 전파의 차이

  • WPF에서는 이벤트의 RoutedEventArgs의 Handled 속성을 true로 설정하면, 이벤트가 더 이상 부모로 전파되지 않습니다.
  • WinForm에서는 이벤트가 발생하면 그 이벤트는 취소할 수 있어도 다른 컨트롤로 전파되는 것을 제어할 수 있는 기능은 없습니다.

이처럼 WinForm은 상대적으로 단순한 이벤트 모델을 사용하는 반면,

WPF는 복잡하지만 더 유연한 이벤트 라우팅 구조를 통해 다양한 UI 동작을 구현할 수 있는 특징이 있습니다.

<유연하다 못해 복잡하다.>

 

5. 소스코드로 알아보는 차이

Winform 예제

using System;
using System.Windows.Forms;

public class WinFormExample : Form
{
    [STAThread]
    public static void Main()
    {
        Application.Run(new WinFormExample());
    }
    
    private Button myButton;
    public WinFormExample()
    {
        myButton = new Button();
        myButton.Text = "Click Me";
        myButton.Location = new System.Drawing.Point(30, 30);
        myButton.Click += MyButton_Click;

        Controls.Add(myButton);
    }

    private void MyButton_Click(object sender, EventArgs e)
    {
        MessageBox.Show("Button Clicked in WinForm!");
    }
}

 

  • MyButton_Click 이벤트 핸들러는 myButton 버튼 컨트롤의 Click 이벤트에서만 발생합니다.
  • 이벤트가 발생한 후 다른 부모 컨트롤로 전파되지 않습니다.

 

 

WPF 예제

using System.Windows;
using System.Windows.Controls;

namespace WpfEventExample
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // StackPanel을 생성하고 Button을 자식으로 추가
            StackPanel stackPanel = new StackPanel();

            // 부모 StackPanel에 이벤트 추가 (Bubbling)
            stackPanel.AddHandler(Button.ClickEvent, new RoutedEventHandler(StackPanel_Click));

            Button myButton = new Button();
            myButton.Content = "Click Me";
            myButton.Click += MyButton_Click;

            stackPanel.Children.Add(myButton);
            this.Content = stackPanel;
        }

        private void MyButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Button Clicked!");
        }

        private void StackPanel_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Event Bubbling to StackPanel!");
        }
    }
}

 

  • StackPanel의 Button.ClickEvent 핸들러는 버블링 이벤트로, 자식 컨트롤(Button)의 이벤트가 발생했을 때 이를 감지하여 처리할 수 있습니다.
  • Button에서 Click 이벤트가 발생해도 StackPanel_Click 메서드가 실행되며, 이처럼 부모 컨트롤에서도 자식의 이벤트를 처리할 수 있는 것이 WPF RoutedEvent의 특징입니다.

 

RoutedEventArgs에서 많이 사용되는 프로퍼티와 내용

WPF의 RoutedEvent 모델에서 이벤트 데이터가 포함된 클래스입니다.

RoutedEventArgs 및 이를 상속하는 파생 클래스들은 WPF에서 이벤트를 처리할 때 사용되는 다양한 정보를 포함하고 있습니다.

많이 사용되는 프로퍼티들은 이벤트의 흐름을 제어하거나 이벤트가 발생한 요소에 대한 정보, 추가적인 사용자 데이터 등을 제공합니다.

아래는 RoutedEventArgs와 그 파생 클래스에서 많이 사용되는 주요 프로퍼티와 설명입니다:

1. RoutedEventArgs의 주요 프로퍼티

Handled

  • 타입: bool
  • 설명: 이벤트가 이미 처리되었는지를 나타냅니다.
  • 용도: 이벤트 핸들러가 이 값을 true로 설정하면 해당 이벤트는 더 이상 다른 부모나 자식 컨트롤로 전달되지 않습니다. 이는 RoutedEvent가 더 이상 버블링(Bubbling)이나 터널링(Tunneling)되지 않도록 하는 중요한 속성입니다.
  • 예제:
     
    private void Button_Click(object sender, RoutedEventArgs e) {
    // 이벤트가 현재 핸들러에서 처리되었음을 명시
    e.Handled = true; }

OriginalSource

  • 타입: object
  • 설명: 이벤트가 최초로 발생한 소스 요소(최하위 UI 요소)를 나타냅니다.
  • 용도: 이벤트가 실제로 발생한 컨트롤이 무엇인지를 확인할 때 사용합니다. 예를 들어, 복잡한 UI 트리 구조에서 이벤트가 최상위 요소에 도달했을 때도 OriginalSource를 사용해 실제로 이벤트를 발생시킨 컨트롤을 확인할 수 있습니다.
  • 예제:
     
    private void StackPanel_Click(object sender, RoutedEventArgs e) {
    // 클릭된 실제 컨트롤 확인
    var sourceControl = e.OriginalSource as FrameworkElement;
    MessageBox.Show($"Original Source: {sourceControl.Name}"); }

Source

  • 타입: object
  • 설명: 현재 이벤트가 처리되고 있는 소스 요소를 나타냅니다. Source는 버블링이나 터널링 도중 바뀔 수 있습니다.
  • 용도: 이벤트의 경로를 따라가면서 현재 이벤트가 처리되는 중인 요소를 추적할 때 사용합니다.
  • 예제:
     
    private void Button_Click(object sender, RoutedEventArgs e) {
    // 현재 이벤트가 처리되고 있는 컨트롤 출력
    var currentControl = e.Source as FrameworkElement;
    MessageBox.Show($"Current Source: {currentControl.Name}"); }

RoutedEvent

  • 타입: RoutedEvent
  • 설명: 현재 이벤트와 연관된 RoutedEvent의 정보를 나타냅니다.
  • 용도: 동일한 핸들러에서 여러 이벤트를 처리할 때, 어떤 이벤트가 발생했는지를 식별할 수 있습니다.
  • 예제:
     
    private void AnyElement_RoutedEventHandler(object sender, RoutedEventArgs e) {
        if (e.RoutedEvent == Button.ClickEvent) {
            MessageBox.Show("Button Clicked Event Handled.");
        }
    }

Timestamp

  • 타입: int
  • 설명: 이벤트가 발생한 시점을 나타내는 타임스탬프 값입니다.
  • 용도: 이벤트 발생 시점을 비교하여 특정 시나리오에서 이벤트가 발생한 순서를 추적할 때 유용합니다.
  • 예제:
     
    private void Button_Click(object sender, RoutedEventArgs e) {
        MessageBox.Show($"Event Timestamp: {e.Timestamp}"); }

2. 파생 클래스의 주요 프로퍼티

RoutedEventArgs를 상속하는 여러 파생 클래스가 있습니다.

이들 중 자주 사용되는 클래스와 그 주요 프로퍼티는 다음과 같습니다:

2.1 MouseEventArgs

  • 적용 범위: 마우스 관련 이벤트 (MouseEnter, MouseMove, MouseLeave 등).
  • 주요 프로퍼티:
    • LeftButton: 마우스 왼쪽 버튼의 상태 (MouseButtonState).
    • RightButton: 마우스 오른쪽 버튼의 상태 (MouseButtonState).
    • MiddleButton: 마우스 가운데 버튼의 상태 (MouseButtonState).
    • GetPosition(UIElement relativeTo): 이벤트 발생 당시 마우스 포인터의 위치를 상대 좌표계로 반환.

2.2 KeyEventArgs

  • 적용 범위: 키보드 관련 이벤트 (KeyDown, KeyUp 등).
  • 주요 프로퍼티:
    • Key: 눌려진 키를 나타냅니다 (Key 열거형).
    • IsDown: 특정 키가 눌린 상태인지 여부.
    • IsUp: 특정 키가 올라간 상태인지 여부.
    • IsRepeat: 키가 눌려진 상태로 반복 입력이 되었는지를 나타냅니다.

2.3 TextChangedEventArgs

  • 적용 범위: 텍스트 변경 이벤트 (TextBox.TextChanged).
  • 주요 프로퍼티:
    • Changes: 텍스트 변경 내역을 나타냅니다.
    • UndoAction: 변경이 발생한 동작이 취소 동작인지 여부를 나타냅니다.

2.4 DragEventArgs

  • 적용 범위: 드래그 앤 드롭 이벤트 (DragEnter, DragLeave, Drop 등).
  • 주요 프로퍼티:
    • Data: 드래그 앤 드롭에 포함된 데이터(IDataObject).
    • AllowedEffects: 허용된 드롭 효과(DragDropEffects).
    • Effects: 실제 드롭된 효과(DragDropEffects).

3. RoutedEventArgs와 EventArgs의 차이

  • EventArgs: 기본 이벤트 데이터 클래스, WinForms 및 일반 .NET 이벤트 처리에서 사용됩니다.
  • RoutedEventArgs: WPF의 이벤트 라우팅 모델에서 사용되며, 이벤트가 자식 또는 부모 컨트롤로 전달되는 것을 지원합니다.

4. Handled 속성 사용 예시

WPF의 이벤트는 부모 요소에서 Handled 속성을 통해 제어될 수 있습니다.

예를 들어, 부모 StackPanel에서 자식 Button의 Click 이벤트가 더 이상 다른 요소에 전달되지 않도록 할 수 있습니다.

private void StackPanel_Click(object sender, RoutedEventArgs e) {
// 이 이벤트가 StackPanel에서 이미 처리되었으므로 더 이상 버블링되지 않도록 설정
e.Handled = true;
}

위의 설정으로 StackPanel에서 Handled를 true로 설정하면 해당 이벤트는 다른 상위 컨트롤로 전파되지 않습니다.