WPFのイベントの バブリング/トンネリング

コンピュータ

WPFのイベントは

子から親へイベントが通知されるがバブリングと

親から子へイベントが通知されるトンネリングあります。

トンネリングイベントには Preview というプレフィックスが付きます。

目的のイベントで処理を行ったら、

e.Handled = true;

をセットすることで、イベントを通知を止めることが出来ます。

イベントの通知の順番を確認するサンプルコードを書いてみました。

XAML:

<Grid PreviewMouseDown="Grid_PreviewMouseDown"
    MouseDown="Grid_MouseDown">
    <Button Content="Click"
        PreviewMouseDown="Button_PreviewMouseDown"
        MouseDown="Button_MouseDown"/>
</Grid>

コードビハイド(C#)

private void Grid_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.Print("Grid Preview");
}

private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.Print("Button Preview");
}

private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.Print("Button");
}

private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.Print("Grid");
}

実行結果

Grid Preview
Button Preview

ButtonはPreviewMouseDownで

e.Handled = true;

を実行しているので、そこでイベントが終了します。

BottonをBorderに変更

<Grid PreviewMouseDown="Grid_PreviewMouseDown"
      MouseDown="Grid_MouseDown">
    <Border Background="LightBlue"
            PreviewMouseDown="Button_PreviewMouseDown"
            MouseDown="Button_MouseDown"
            Width="100"
            Height="50"/>
</Grid>

実行結果

Grid Preview
Button Preview
Button
Grid

Borderはそのままイベントが流れるので、
Gird→Button(Border)→Button(Border)→Grid
とイベントが折り返されます。

現実的に、全てのイベントを書くことは、余り考えられません。

Gridで受け取る、PreviewMouseDown(トンネリング・親 → 子)と

Buttonで受け取る、MouseDown(バブリング・子 → 親)

のいずれかを使う事に成ると思います。

コメント