検索
連載

第3回 XAMLコードから生成されるプログラム・コードを理解する ―― XAML(2): WPF固有機能の基礎 ――連載:WPF入門(4/4 ページ)

XAMLコードから自動生成される中間生成物のプログラム・コード、依存関係プロパティとルーティング・イベントを解説。WPFの内部的な挙動を理解しよう。

Share
Tweet
LINE
Hatena
前のページへ |       

■ルーティング・イベント

 依存関係プロパティと同様に、WPFでは「ルーティング・イベント(routed event)」と呼ばれる特殊なイベント通知機構を持っている(プロパティの場合と同様に、通常のイベントを「CLRイベント」と呼んで区別する)。ルーティング・イベントは依存関係プロパティのイベント版といえる。

 CLRイベントとの差は、発生したイベントが要素ツリーをたどって“ルーティング”されるところにある。ルーティングの方針には以下の3種類がある。

  • 直接(Direct): イベント発生源となる要素自身のイベント・ハンドラのみが呼び出される。
  • トンネル(Tunnel): 要素ツリーのルートからイベント発生源となる要素に向かって、要素ツリーを掘り進むようにイベント・ハンドラが呼び出される。
  • バブル(Bubble): イベント発生源となる要素からルートに向かって、要素ツリーをたどりながら、浮かび上がるようにイベント・ハンドラが呼び出される。

ルーティング・イベントの定義

 List 8にルーティング・イベントの定義例を示す。

public partial class MyControl : UserControl
{
  public static readonly RoutedEvent ClickEvent =
    EventManager.RegisterRoutedEvent(
      "Click", RoutingStrategy.Bubble,
      typeof(RoutedEventHandler), typeof(MyControl));
 
  public event RoutedEventHandler Click
  {
    add { AddHandler(ClickEvent, value); }
    remove { RemoveHandler(ClickEvent, value); }
  }
}

Public Class MyControl

  Public Shared ReadOnly ClickEvent As RoutedEvent = _
    EventManager.RegisterRoutedEvent( _
      "Click", RoutingStrategy.Bubble, _
      GetType(RoutedEventHandler), GetType(MyControl))

  Public Custom Event Click As RoutedEventHandler
    AddHandler(ByVal value As RoutedEventHandler)
      MyBase.AddHandler(ClickEvent, value)
    End AddHandler
    RemoveHandler(ByVal value As RoutedEventHandler)
      MyBase.RemoveHandler(ClickEvent, value)
    End RemoveHandler
    RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
      MyBase.RaiseEvent(e)
    End RaiseEvent
  End Event

End Class

List 8: ルーティング・イベントの定義(上:C#、下:VB)

 依存関係プロパティと同様に、RoutedEventクラス(System.Windows名前空間)のインスタンス自体は辞書のキー(+メタデータ)のようなものであり、実際にイベント・ハンドラを保持するのはUIElementクラス(System.Windows名前空間)(の子クラス)のインスタンスである。ルーティング・イベントを格納する静的フィールドの名前は「イベント名+Event」とする。

 ルーティング・イベントもWPFへの登録が必要で、こちらはEventManagerクラス(System.Windows名前空間)のRegisterRoutedEventメソッドを用いる。引数は、イベント名、ルーティング方針、イベント・ハンドラの型、および、イベント発生源となる型である。

 UIElementクラスのインスタンスへのイベント・ハンドラの追加/削除は、UIElement.AddHandler/RemoveHandlerメソッドを用いて行う。依存関係プロパティの定義の際に対応するCLRプロパティを定義したのと同様に、ルーティング・イベントの場合にも対応するCLRイベントを定義しておく(上記の例ではClickイベントが該当)。

ルーティング・イベントの利用例

 ルーティング・イベントを利用することで、UI要素で発生したイベントを、その親要素で一括して処理できる。例えば、<ListBox>要素のような、コレクションとして子要素を持つようなもので、子要素で発生したイベントを<ListBox>要素自身で一括して処理したい場合などに便利である。

 List 9にその一例を挙げる。本連載でまだ説明していないデータ・テンプレートなどの機能を使っているが、詳細は次回以降で説明していく。

 ここでのポイントは<ListBox>要素でButton.Clickイベントを拾い、子要素として追加した<Button>要素のClickイベントを一括処理している部分である。<Button>要素1つ1つにイベント・ハンドラを追加しなくても、<ListBox>要素側の1度きりの追加でイベントの処理が可能になっている。

<UserControl x:Class="MyControl"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Grid>
    <ListBox Name="list" Button.Click="Button_Click">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <Button Content="{Binding}" />
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
  </Grid>
</UserControl>

using System.Windows;
using System.Windows.Controls;
 
public partial class MyControl : UserControl
{
  public MyControl()
  {
    InitializeComponent();
 
    this.list.ItemsSource = new[]
    {
      "A", "B", "C",
    };
  }
 
  private void Button_Click(object sender, RoutedEventArgs e)
  {
    var button = e.OriginalSource as Button;
    MessageBox.Show(button.DataContext.ToString());
  }
}

Public Class MyControl

  Public Sub New()
    InitializeComponent()
    Me.list.ItemsSource = {"A", "B", "C"}
  End Sub

  Private Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim button As Button = e.OriginalSource
    MessageBox.Show(button.DataContext.ToString())
  End Sub

End Class

List 9: ルーティング・イベントの利用例(上:XAML、中:C#、下:VB)


 次回はスタイルやテンプレートなどの仕組みについて説明を行っていく。

「連載:WPF入門」のインデックス

連載:WPF入門

Copyright© Digital Advantage Corp. All Rights Reserved.

前のページへ |       
ページトップに戻る