トップ > Tech > CSharp > WPF > コンテキストメニューが開かれたコントロールを取得する

コンテキストメニューが開かれたコントロールを取得する

はじめに

WPF では ContextMenu プロパティに ContextMenu を設定するだけで コンテキストメニューの表示が可能だが、そのメニュー項目がクリックされたときなどに コンテキストメニューが開かれた元のコントロールが簡単にわからない。

ここでは、元のコントロールの取得方法を示す。

概要

まず、MenuItem の Click イベントを考える。イベント引数(RoutedEventArgs)の e の Source プロパティにはイベントの発生元が設定されているので、e.Source は MenuItem である "はず" である。

ということで、e.Source を MenuItem にキャストし、それの MenuItem.Parent プロパティを調べれば、親の ContextMenu が得られる。

次に ContextMenu には PlacementTarget プロパティがある。これは ContextMenu が表示される際の表示位置の基準となるオブジェクトを示すプロパティである。ContextMenu を開く際にこのプロパティを意図的に設定しなければ、右クリックしたコントロールが格納されるらしい。

よって、この ContextMenu.PlacementTarget プロパティが開かれた元のコントロールということになる。

つまり、キャストを省略すれば、

e.Source.Parent.PlacementTarget

が元のコントロールを示す。 実際には、Source や Parent は object や DependencyObject なので、次のようにキャストをしながら、さかのぼればよい(面倒なので、ここでは as 演算子をキャストと呼ぶ)。

((e.Source as MenuItem).Parent as ContextMenu).PlacementTarget

ただし、ContextMenu.PlacementTarget を独自に設定している場合は、この方法はおそらく不可能である。

サンプル

ListBox のアイテムに設定したコンテキストメニューのアイテムがクリックされたときのイベントの例。ListBox のアイテムはそれぞれ ListBoxItem であり、それらにバインディングされたオブジェクトは ListBoxItem.DataContext で取得できる。

private void MenuItem_Click(object sender, RoutedEventArgs e)
{
  var target = ((e.Source as MenuItem).Parent as ContextMenu).PlacementTarget;
  if (target is ListBoxItem)
  {
      var item = target as ListBoxItem;
      if (item.DataContext is XXX)
      {
        // ほにゃらら
      }
  }
}
(2011/03/03 17:22:47)
22869
プロフィール

Kenz Yamada(山田研二)。1984年生。大阪。ちょっとずつ好きなプログラム作ってます。 好きなものはカメラと旅行。ガジェットや身の回り、ちょっとこだわります。 詳しくは Web mixi で。

Bookmark and Share