VB のたまご

作成日: 2017/03/07, 更新日: 2017/03/07



ルーティングイベント2

  •  前回に引き続き、ルーティングイベントの説明です。前回はバブルイベントの説明でした。

  • スポンサーリンク


トンネリングイベント

  •  ルーティングイベントがバトンリレーだというのならば、上昇の他に下降もあるはずです。 その考え方は合っていて、逆順に進んでいくトンネリングイベントというものがあります。 とりあえず、どう動くか見てみましょう。 ちなみに、トンネリングイベントの代表として、PreviewClick があるかと思ってみたらなかったので、PreviewMouseUp で代用しています。 トンネリングイベントの命名規則として、「Preview~」と頭に付けるのが一般的です。

  • <Window x:Class="RoutedEventWindow4"
            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:w05_WpfSystem"
            mc:Ignorable="d"
            Title="RoutedEventWindow4" Height="300" Width="300">
    
        <Grid Name="grid1" Button.PreviewMouseUp="Button_PreviewMouseUp">
    
            <StackPanel Name="stackpanel1" Margin="10" Button.PreviewMouseUp="Button_PreviewMouseUp">
    
                <Button Name="button1" Content="button1" PreviewMouseUp="Button_PreviewMouseUp" />
                <Button Name="button2" Content="button2" PreviewMouseUp="Button_PreviewMouseUp" />
    
            </StackPanel>
    
        </Grid>
    
    </Window>
    

    Public Class RoutedEventWindow4
    
        Private Sub Button_PreviewMouseUp(sender As Object, e As MouseButtonEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            Console.WriteLine($"{calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
    End Class
    

  •  実行してボタンをクリックしてみてください。例えば、button1 をクリックしたときの動作結果が以下です。

  • 出力結果
    grid1, System.Windows.Controls.Grid
    stackpanel1, System.Windows.Controls.StackPanel
    button1, System.Windows.Controls.Button
    

  •  つまり、トンネリングイベントはこういう風な動き方になります。

  • <Grid Name="grid1" Button.PreviewMouseUp="Button_PreviewMouseUp"> ←①イベントキャッチと処理
    
        <StackPanel Name="stackpanel1" Margin="10" Button.PreviewMouseUp="Button_PreviewMouseUp"> ←②イベントキャッチと処理
    
            <Button Name="button1" Content="button1" PreviewMouseUp="Button_PreviewMouseUp" /> ←(0)イベント発生、③イベントキャッチと処理
            <Button Name="button2" Content="button2" PreviewMouseUp="Button_PreviewMouseUp" />
    
        </StackPanel>
    
    </Grid>
    

  •  コントロール内にコントロールを配置した際に、親子関係として表現する場合がありますが、 バブルイベントは、家系図の範囲で、自分→父→祖父→、、、みたいに、イベント発生者から過ぎ去っていく感じ、 トンネリングイベントは、家系図の範囲で、、、、→祖父→父→自分みたいに、イベント発生者に近づいてくる感じです。 逆に分かりづらいかなorz。

  •  ちなみに私の間違いですが、トンネリングイベントの動作を、誤った動き方として認識してしまったことがあります。

  • <Button name="button1" Click="xxx"> ←①イベント発生元、イベントキャッチと処理
        <Button name="button2"> ←②イベントキャッチと処理
            <Button name="button3" /> ←③イベントキャッチと処理
        </Button>
    </Button>
    

  •  バブルイベント的に始まり、トンネリングイベント的に遠ざかるような、ごっちゃな動作です。 つまり、上昇の反対は下降だから、くだっていくんでしょ?みたいな理解の仕方ですが、トンネリングイベントはこういう動作はしません。

  • スポンサーリンク


イベントハンドラを分けた場合

  •  基本的に変わらないんですが、次のサンプルとして、今度は1イベント1イベントハンドラな状態で見てみましょう。 バブルイベントとトンネリングイベントの両方です。

  • <Window x:Class="RoutedEventWindow5"
            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:w05_WpfSystem"
            mc:Ignorable="d"
            Title="RoutedEventWindow5" Height="300" Width="300">
    
        <Grid 
            Name="grid1"
            MouseUp="Grid_MouseUp" 
            PreviewMouseUp="Grid_PreviewMouseUp">
    
            <StackPanel 
                Name="stackpanel1"
                Margin="10" 
                MouseUp="StackPanel_MouseUp" 
                PreviewMouseUp="StackPanel_PreviewMouseUp">
    
                <Button 
                    Name="button1"
                    Content="マウスの右ボタンをクリックしてね" 
                    MouseUp="Button_MouseUp" 
                    PreviewMouseUp="Button_PreviewMouseUp" />
    
            </StackPanel>
    
        </Grid>
    
    </Window>
    

    Public Class RoutedEventWindow5
    
        Private Sub Grid_MouseUp(sender As Object, e As MouseButtonEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            Console.WriteLine($"Grid_MouseUp / {calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
        Private Sub Grid_PreviewMouseUp(sender As Object, e As MouseButtonEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            Console.WriteLine($"Grid_PreviewMouseUp / {calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
        Private Sub StackPanel_MouseUp(sender As Object, e As MouseButtonEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            Console.WriteLine($"StackPanel_MouseUp / {calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
        Private Sub StackPanel_PreviewMouseUp(sender As Object, e As MouseButtonEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            Console.WriteLine($"StackPanel_PreviewMouseUp / {calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
        Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            Console.WriteLine($"Button_MouseUp / {calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
        Private Sub Button_PreviewMouseUp(sender As Object, e As MouseButtonEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            Console.WriteLine($"Button_PreviewMouseUp / {calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
    End Class
    

    出力結果
    Grid_PreviewMouseUp / grid1, System.Windows.Controls.Grid
    StackPanel_PreviewMouseUp / stackpanel1, System.Windows.Controls.StackPanel
    Button_PreviewMouseUp / button1, System.Windows.Controls.Button
    Button_MouseUp / button1, System.Windows.Controls.Button
    StackPanel_MouseUp / stackpanel1, System.Windows.Controls.StackPanel
    Grid_MouseUp / grid1, System.Windows.Controls.Grid
    

  •  出力結果を見ると、トンネリングイベントが発生した後、バブルイベントが発生していることが分かります。 最初はトンネリングイベントが走るんですね。

  •  ちなみに、マウスの「左」ボタンでボタンコントロールをクリックすると、PreviewMouseUp イベントは発生するのですが、MouseUp イベントは発生しませんでした。 よくよく調べてみると、マウスの左ボタンをクリックしたい場合は、「MouseLeftButtonUp」、「PreviewMouseLeftButtonUp」と、厳格に左のボタンについてのイベントを記載する必要があるみたいです。

ルーティング中のキャンセル

  •  イベントハンドラを紐づけている場合、紐づけているコントロールの全ルートを通ることになります。 何らかの処理で途中で処理を終えたので、後続のイベントには何もさせたくない場合があります。 それではどうやって対処するのか、サンプルを見てみましょう。

  • <Window x:Class="RoutedEventWindow6"
            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:w05_WpfSystem"
            mc:Ignorable="d"
            Title="RoutedEventWindow6" Height="300" Width="300">
    
        <Grid Name="grid1" Button.Click="Button_Click">
    
            <StackPanel Name="stackpanel1" Margin="10" Button.Click="Button_Click">
    
                <Button Name="button1" Content="button1" Click="Button_Click" />
                <Button Name="button2" Content="button2" Click="Button_Click" />
    
            </StackPanel>
    
        </Grid>
    
    </Window>
    

    Public Class RoutedEventWindow6
    
        Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    
            Dim calledControl = CType(sender, FrameworkElement)
            If calledControl.Name = "button1" Then
                e.Handled = True
            End If
    
            Console.WriteLine($"{calledControl.Name}, {calledControl.GetType()}")
    
        End Sub
    
    End Class
    

    出力結果
    button1, System.Windows.Controls.Button
    

  •  ルーティングを停止したい場合は、RoutedEventArgs.Handled プロパティに True をセットします。 このサンプルでは、button1 の時の Button_Click イベントハンドラ内で e.Handled に True をセットしているので、以降の Button_Click が走らなくなっています。