nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

ルーティングイベントの学習 [C#][WPF]

ルーティングイベントとは

  • 観点を機能に置いた場合、イベントを生成したオブジェクト上だけでなく、要素ツリー内の複数のリスナー上でハンドラーを呼び出すことができる種類のイベント
  • 観点を実装に置いた場合、ルーティング イベントは、RoutedEvent クラスのインスタンスによってサポートされる CLR イベントであり、Windows Presentation Foundation (WPF) イベント システムによって処理される

サンプル例

Buttonが3つあり、親要素にStatckPanelがあり、さらに、親要素にBorderがあり、さらに親要素にWindowがある画面。

Buttonのどれかを押すと、StackPanelのClickイベントハンドラが呼ばれ、次に、BorderのClickイベントハンドラが呼ばれ、次に、WindowsのClickイベントハンドラが呼ばれる。

f:id:nprogram:20180418235227p:plain

f:id:nprogram:20180418235435p:plain

f:id:nprogram:20180418235447p:plain

f:id:nprogram:20180418235456p:plain

[MainWindow.xaml]

<Window x:Class="WpfApp1.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"
        mc:Ignorable="d"
        Title="MainWindow"
        SizeToContent="WidthAndHeight" Button.Click="WindowClickHandler">
    <Grid>
        <Border Height="50" Width="Auto" BorderBrush="Gray" BorderThickness="1" Button.Click="BorderClickHandler">
            <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="StackPanelClickHandler">
                <Button Name="YesButton" Width="Auto" >Yes</Button>
                <Button Name="NoButton" Width="Auto" >No</Button>
                <Button Name="CancelButton" Width="Auto" >Cancel</Button>
            </StackPanel>
        </Border>
    </Grid>
</Window>

[MainWindow.xaml.cs]

using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void StackPanelClickHandler(object sender, RoutedEventArgs e)
        {
            FrameworkElement feSource = e.Source as FrameworkElement;
            switch (feSource.Name)
            {
                case "YesButton":
                    MessageBox.Show("[StackPanel] Push Yes Button!");
                    break;
                case "NoButton":
                    MessageBox.Show("[StackPanel] Push No Button!");
                    break;
                case "CancelButton":
                    MessageBox.Show("[StackPanel] Push Cancel Button!");
                    break;
            }
            // e.Handledをtrueにしないかぎり、親要素にボタンクリックイベントに伝搬していく
            e.Handled = false;
        }

        private void BorderClickHandler(object sender, RoutedEventArgs e)
        {
            FrameworkElement feSource = e.Source as FrameworkElement;
            switch (feSource.Name)
            {
                case "YesButton":
                    MessageBox.Show("[Border] Push Yes Button!");
                    break;
                case "NoButton":
                    MessageBox.Show("[Border]Push No Button!");
                    break;
                case "CancelButton":
                    MessageBox.Show("[Border]Push Cancel Button!");
                    break;
            }
            // e.Handledをtrueにしないかぎり、親要素にボタンクリックイベントに伝搬していく
            e.Handled = false;
        }

        private void WindowClickHandler(object sender, RoutedEventArgs e)
        {
            FrameworkElement feSource = e.Source as FrameworkElement;
            switch (feSource.Name)
            {
                case "YesButton":
                    MessageBox.Show("[Window] Push Yes Button!");
                    break;
                case "NoButton":
                    MessageBox.Show("[Window]Push No Button!");
                    break;
                case "CancelButton":
                    MessageBox.Show("[Window]Push Cancel Button!");
                    break;
            }
            e.Handled = true;
        }
    }
}

ハンドラの引数であるRoutedEventArgsに定義されているHandledプロパティを使用すると、イベントルーティングを制御できます。 ハンドラ内でHandledプロパティをtrueにセットした場合、それ以降のイベントルーティングは呼び出されません。 例えば、StackPanelClickHandlerメソッドのe.Handled = falsee.Handled = trueに変更すると、イベントが親要素(Border)に伝搬しなくなります。

RoutedEventについては、この後、記載します。

参考ページ

  • ルーティング イベントの概要

https://msdn.microsoft.com/ja-jp/library/ms742806(v=vs.100).aspx