9장. WPF 이벤트 라우팅(RoutedEvent), 버블링/ 터널링/다이렉트 이벤트

9장. WPF 이벤트 라우팅(RoutedEvent), 버블링/ 터널링/다이렉트 이벤트

참조

목적

  • WPF 이벤트 라우팅(RoutedEvent), 버블링/터널링/다이렉트 이벤트에 대해서 학습합니다.

정의

  • 이벤트 라우팅은 어떤 이벤트가 컨트롤의 하위 또는 상위로 전달되는 것 을 이야기하며 WPF에서 광범위하게 이용되는 방법입니다.
  • 이벤트 라우팅은 세가지로 분류할 수 있는데 이벤트가 발생했을 때 현재 컨트롤에서 상위로 올라가면서 전달되는 경우를 "버블링 이벤트(Bubbleing Event)" 라고 하고 반대로 자식 컨트롤로 전달되는 경우를 "터널링(Tunneling Event)" 라고 합니다. 하나의 엘리먼트에서만 발생하게 된다면 다이렉트 이벤트(Direct Event) 라고 합니다.
  • 터널링 이벤트 의 경우 접두사로 preview를 붙이는데, PreviewMouseDown, PreviewDragDown 등으로 쓰여지는 것들을 Tunneling 이벤트라고 이해하면 됩니다.
  • 터널링이벤트 는 최상위 부모 컨트롤로부터 자기자신까지 이벤트가 진행되는 것인데, 이벤트가 자식 요소에게 전달되기 전에 부모의 이벤트가 먼저 호출되므로 부모 이벤트가 먼저 호출할 수 있는 기회를 제공하며, 자식의 이벤트 발생을 막거나 자식 이벤트 처리 전에 부모 요소가 무엇인가 수행할 필요가 있는 경우에 유용합니다.
  • 이벤트 핸들러 메서드는 RoutedEventArgs 매개변수를 가지는데 Source 속성을 통해 실제 이벤트를 발생시킨 요소에 대한 참조를 제공하며, 이 속성은 여러 요소에서 발생한 이벤트를 동일한 방법으로 처리하고자 할 때 특히 유용합니다.

1

  • WPF의 라우팅된 이벤트에서 object sender는 이벤트를 등록한 객체, RoutedEventArgs의 Source 속성은 실제 이벤트를 발생시킨 객체를 의미합니다.
  • WPF의 이벤트 라우팅 모델은 자동으로 이벤트를 상위 객체로 라우팅 시켜줍니다. (버블링 이벤트)

Bubbleing(자식에서 부모로 위로 올라감) 실습

MainWindow.xaml

<Window x:Class="WPF09_Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF09_Test"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="350"
        ButtonBase.Click="Window_Click">
    <Grid>
        <StackPanel Margin="20" ButtonBase.Click="StackPanel_Click">
            <StackPanel Margin="10">
                <TextBlock x:Name="txt1" FontSize="18"
                           Margin="5" 
                           Text="This is a TextBlock1"/>

                <TextBlock x:Name="txt2" FontSize="18"
                           Margin="5"
                           Text="This is a TextBlock2"/>

                <TextBlock x:Name="txt3" FontSize="18"
                           Margin="5"
                           Text="This is a TextBlock3"/>
            </StackPanel>
            <Button Margin="10" Content="Click me"
                    Click="Button_Click"
                    Width="80"/>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;

namespace WPF09_Test
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Click(object sender, RoutedEventArgs e)
        {
            txt3.Text = "Click event is bubbled to Window";
        }

        private void StackPanel_Click(object sender, RoutedEventArgs e)
        {
            txt2.Text = "Click event is bubbled to Stack Panel";
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            txt1.Text = "Button is Clicked";
        }
    }
}

실행 결과

2

  • 상위 객체로 라우팅 되는 것을 막으려면 RoutedEventArgs의 Handled 속성을 true로 설정하면 된다.
  • 버튼 클릭 이벤트에 "e.Handled = true" 라고 하면 버튼까지만, 스택 패널 클릭 이벤트에 "e.Handled = true" 라고 한다면 스택 패널 까지만 이벤트가 전달됩니다.

MainWindow.xaml.cs

using System.Windows;

namespace WPF09_Test
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Click(object sender, RoutedEventArgs e)
        {
            txt3.Text = "Click event is bubbled to Window";
        }

        private void StackPanel_Click(object sender, RoutedEventArgs e)
        {
            txt2.Text = "Click event is bubbled to Stack Panel";
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            txt1.Text = "Button is Clicked";
            e.Handled = true; //상위로 Routing  되는 걸 막으려면 e.Handled = true 설정하면 된다.
        }
    }
}

실행 결과

3

  • Preview 이벤트에 Handled 속성을 지정하면 Preview 이벤트의 터널링이 중단될 뿐만 아니라 버블링 이벤트의 발생도 중단 됩니다.

Tunneling(부모에서 자식으로) 실습

MainWindow.xaml

<Window x:Class="WPF09_Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF09_Test"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="350"
        PreviewMouseDown="Window_PreviewMouseDown">
    <StackPanel Height="120" HorizontalAlignment="Center"
                VerticalAlignment="Center" Width="200"
                Background="Transparent"
                PreviewMouseDown ="StackPanel_PreviewMouseDown">
        <Border Margin="20" Padding="5" Background="LightYellow"
                BorderBrush="SteelBlue" BorderThickness="3 5 3 5"
                CornerRadius="3"
                VerticalAlignment="Top">
            <Button Margin="20" Height="50" Width="50"
                    PreviewMouseDown="Button_PreviewMouseDown"/>
        </Border>
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System.Windows;

namespace WPF09_Test
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : Window
    {
        string mouseActivity = string.Empty;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            mouseActivity = "PreviewMouseDown Window\n";
            MessageBox.Show(mouseActivity);
        }

        private void StackPanel_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            mouseActivity = "PreviewMouseDown StackPanel \n";
            MessageBox.Show(mouseActivity);
        }

        private void Button_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            mouseActivity = "PreviewMouseDown Button \n";
            MessageBox.Show(mouseActivity);
        }
    }
}

실행 결과

4

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY