[WPF] Buttonをマウスクリック/タッチしたときのイベントの流れ(親子関係あり)


全体もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f

イベント関連のもくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f#%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E9%96%A2%E9%80%A3wpfxaml

やりたいこと

ボタン単品を指でタッチしたりクリックしたときのイベントの流れを以前の記事で試してみたが、今度は親子関係のあるコントロール、例えばGridの中に入ってるButtonを押したときにどういうイベントの流れになるのかを今一度確認したい。

実験プログラム

コード

以前の記事で使ったものをほぼ流用する。ただし、Gridの中にButtonを入れてやる。

MainWindow.xaml
<Window x:Class="WpfApp64.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:WpfApp64"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="0*"/>
        </Grid.RowDefinitions>

        <Grid x:Name="MainGrid"
              Background="#66FF0000"
              Grid.Row="0"
              Margin="50"
              IsManipulationEnabled="False" 
              ManipulationStarting="MainGrid_ManipulationStarting" 
              ManipulationDelta="MainGrid_ManipulationDelta"
              ManipulationCompleted="MainGrid_ManipulationCompleted"

              PreviewMouseDown=             "MainGrid_PreviewMouseDown"             MouseDown="MainGrid_MouseDown"
              PreviewMouseUp=               "MainGrid_PreviewMouseUp"               MouseUp="MainGrid_MouseUp"
              PreviewTouchDown=             "MainGrid_PreviewTouchDown"             TouchDown="MainGrid_TouchDown"
              PreviewTouchUp=               "MainGrid_PreviewTouchUp"               TouchUp="MainGrid_TouchUp"
              PreviewStylusDown=            "MainGrid_PreviewStylusDown"            StylusDown="MainGrid_StylusDown"
              PreviewStylusUp=              "MainGrid_PreviewStylusUp"              StylusUp="MainGrid_StylusUp"
              PreviewMouseLeftButtonDown=   "MainGrid_PreviewMouseLeftButtonDown"   MouseLeftButtonDown="MainGrid_MouseLeftButtonDown"
              PreviewMouseLeftButtonUp=     "MainGrid_PreviewMouseLeftButtonUp"     MouseLeftButtonUp="MainGrid_MouseLeftButtonUp"
              PreviewMouseRightButtonDown=  "MainGrid_PreviewMouseRightButtonDown"  MouseRightButtonDown="MainGrid_MouseRightButtonDown"
              PreviewMouseRightButtonUp=    "MainGrid_PreviewMouseRightButtonUp"    MouseRightButtonUp="MainGrid_MouseRightButtonUp">

            <Button Margin="50" Content="ボタン"
                Grid.Row="0"
                Click="Button_Click"
                PreviewMouseDown="Button_PreviewMouseDown"                          MouseDown="Button_MouseDown"
                PreviewMouseUp="Button_PreviewMouseUp"                              MouseUp="Button_MouseUp"
                PreviewTouchDown="Button_PreviewTouchDown"                          TouchDown="Button_TouchDown"
                PreviewTouchUp="Button_PreviewTouchUp"                              TouchUp="Button_TouchUp"
                PreviewStylusDown="Button_PreviewStylusDown"                        StylusDown="Button_StylusDown"
                PreviewStylusUp="Button_PreviewStylusUp"                            StylusUp="Button_StylusUp"
                PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown"      MouseLeftButtonDown="Button_MouseLeftButtonDown"
                PreviewMouseLeftButtonUp="Button_PreviewMouseLeftButtonUp"          MouseLeftButtonUp="Button_MouseLeftButtonUp"
                PreviewMouseRightButtonDown="Button_PreviewMouseRightButtonDown"    MouseRightButtonDown="Button_MouseRightButtonDown"
                PreviewMouseRightButtonUp="Button_PreviewMouseRightButtonUp"        MouseRightButtonUp="Button_MouseRightButtonUp"
            />
        </Grid>

        <Button Name="KirikaeBtn" 
                Width="150" Height="40" 
                HorizontalAlignment="Left" VerticalAlignment="Top" 
                Content="false"
                Click="IsManipulationEnabledChange"/>
    </Grid>
</Window>

画面見た目

結果

Gridの中のButtonを指で押したとき

出力

下記のような出力になった。

MainGrid_PreviewStylusDown
Button_PreviewStylusDown
Button_StylusDown
MainGrid_StylusDown
MainGrid_PreviewTouchDown
Button_PreviewTouchDown
Button_TouchDown
MainGrid_TouchDown
MainGrid_PreviewMouseLeftButtonDown
MainGrid_PreviewMouseDown
Button_PreviewMouseLeftButtonDown
Button_PreviewMouseDown
MainGrid_PreviewStylusUp
Button_PreviewStylusUp
Button_StylusUp
MainGrid_StylusUp
MainGrid_PreviewTouchUp
Button_PreviewTouchUp
Button_TouchUp
MainGrid_TouchUp
MainGrid_PreviewMouseLeftButtonUp
MainGrid_PreviewMouseUp
Button_PreviewMouseLeftButtonUp
Button_PreviewMouseUp
Button_Click

図で書くと、下記のようになった。

クセが強いと思った部分①

単品のButtonを押したときにもクセが強いと思った点だが、
<Button>では、PreviewMouseLeftButtonDownに対応するMouseLeftButtonDownなど、マウスを押したとき系イベントのトンネリングイベントは来るが、バブリングイベントは来ない。

クセが強いと思った部分②

①にも関連するが、PreviewMouseLeftButtonDownPreviewMouseDownは、

  • PreviewMouseLeftButtonDownが親⇒子に行ってからPreviewMouseDownが親⇒子に行くのではなく、
  • PreviewMouseLeftButtonDownが親だけに行ったらPreviewMouseDownが親だけに行き、PreviewMouseLeftButtonDownが子だけに行ってPreviewMouseDownが子だけに行く

という流れになる。
StylusDownTouchDownは何となくイメージ通りだが、Mouse系はお互いのイベントが関係していて、出る順番が決まっているっぽい。

Gridの中のButtonをマウスでクリックしたとき

上の結果から、Stylus系イベントとTouch系イベントをまるっと抜いたイベントが来る。

考察

すべてのイベントが、一貫したルール(トンネリングイベントが親⇒子の方向に伝わり、次にバブリングイベントが子⇒親の方向に伝わる)のではなく、イベント個々で伝わり方に色々個性があるっぽい。
そのあたりは、個々のイベントのMSの解説をしっかり読んで、かつ使う前にどういう動作、伝わり方をするか実験してから使った方がよさそう。

参考

MSかずきさん イベント解説
https://qiita.com/okazuki/items/43e98bf7107c3e710177