locked
TreeView上のContextMenuで右クリックしたオブジェクトを取得する方法 RRS feed

  • 質問

  • いつもお世話になります。
    環境はSilverlight4、VS2010、.NET4(C#)です。

    下記XAMLコードのように、HierarchicalDataTemplateを使ってTreeViewにデータバインドしています。

    <!-- メンバー -->
    <sdk:HierarchicalDataTemplate x:Key="ChildTemplate">
        <TextBlock Text="{Binding Path=Name}" Height="14" />
    </sdk:HierarchicalDataTemplate>

    <!-- グループ -->
    <sdk:HierarchicalDataTemplate x:Key="NameTemplate"
                              ItemsSource="{Binding Path=Members}"
                              ItemTemplate="{StaticResource ChildTemplate}">
        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Height="14">
            <cinput:ContextMenuService.ContextMenu>
                <cinput:ContextMenu>
                    <cinput:MenuItem Header="名前を変更" Click="groupItemMenuChangeName_Click" />
                    <cinput:MenuItem Header="削除" />
                </cinput:ContextMenu>
            </cinput:ContextMenuService.ContextMenu>
        </TextBlock>
    </sdk:HierarchicalDataTemplate>


    表示される各項目はTextBlockですので、そこにContextMenuを追加しているのですが、
    コード中のgroupItemMenuChangeName_Clickが呼ばれた時、どの項目を右クリックしたかが分かりません。
    どのように取得すればよいのでしょうか。
    2011年8月10日 3:34

回答

  • 直接的な回答ではないのですが、Clickイベントを発生させる前、つまりMouseRightButtonDownイベントで該当オブジェクトを選択させ、
    ClickイベントでSelectedItemを取得する方法は使えないでしょうか。

    XAMLでTreeViewのMouseRightButtonDownイベントハンドラを定義し、次のように書きます。

    private void treeView_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
      foreach (var item in VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(Application.Current.RootVisual), treeView))
      {
        var treeViewItem = item as TreeViewItem;
        if (treeViewItem != null)
        {
          treeView.SelectItem(treeViewItem.DataContext);
          break;
        }
      }
    }
    
    
    VisualTreeHelperを使って、マウスカーソル上のアイテムを取得し、そのアイテムを選択状態(SelectedItemに代入される)にしています。
    foreach文をbreakしているのは、VisualTreeHelperの仕様として、TreeViewの子アイテムにカーソルがある場合、子アイテムから順に親アイテムも取得してしまうからです。

    このあと、Clickイベントハンドラ内でTreeViewのSelectedItemを取得すると、私の場合うまくいったのですかいかがでしょうか。

    • 回答としてマーク femp 2011年8月10日 5:26
    2011年8月10日 5:00
  • > 私の環境化では、教えて頂いたコードのtreeView.SelectItem()が利用できなかったため(存在しないメソッドの模様)

    私のソースをよくみたところ、SelectItemメソッドはSilverlightToolkitで定義されている拡張メソッドでした。
    アセンブリ System.Windows.Controls.Toolkit.dll 内の System.Windows.Controls.TreeViewExtensions 静的クラスで定義されていました。
    失礼しました。

    • 回答としてマーク femp 2011年8月10日 7:08
    2011年8月10日 6:35

すべての返信

  • 直接的な回答ではないのですが、Clickイベントを発生させる前、つまりMouseRightButtonDownイベントで該当オブジェクトを選択させ、
    ClickイベントでSelectedItemを取得する方法は使えないでしょうか。

    XAMLでTreeViewのMouseRightButtonDownイベントハンドラを定義し、次のように書きます。

    private void treeView_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
      foreach (var item in VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(Application.Current.RootVisual), treeView))
      {
        var treeViewItem = item as TreeViewItem;
        if (treeViewItem != null)
        {
          treeView.SelectItem(treeViewItem.DataContext);
          break;
        }
      }
    }
    
    
    VisualTreeHelperを使って、マウスカーソル上のアイテムを取得し、そのアイテムを選択状態(SelectedItemに代入される)にしています。
    foreach文をbreakしているのは、VisualTreeHelperの仕様として、TreeViewの子アイテムにカーソルがある場合、子アイテムから順に親アイテムも取得してしまうからです。

    このあと、Clickイベントハンドラ内でTreeViewのSelectedItemを取得すると、私の場合うまくいったのですかいかがでしょうか。

    • 回答としてマーク femp 2011年8月10日 5:26
    2011年8月10日 5:00
  • 回答ありがとうございます。
    教えて頂いた方法でうまくいきました。

    少し戸惑ってしまいましたが、上記イベントハンドラを設定するのは
    TreeView要素ではなく、項目のTextBlockで良いんですよね?
    TreeViewに対して設定すると、項目上で右クリックしても反応しませんでしたが、
    (項目外のTreeView領域内なら反応した)
    TextBlockに対して設定したらうまくいきました。
    #教えて頂いた処理内容であれば、どっちでも関係ないですよね多分

    大変助かりました。
    ありがとうございました。


    追記:
    私の環境化では、教えて頂いたコードのtreeView.SelectItem()が利用できなかったため(存在しないメソッドの模様)
    代わりに
    treeViewItem.IsSelected = true;
    として対応したことを、参考情報として追記させて頂きます。
    ExpressionBlendだと存在するとか、そういう違いなんだろうか・・・
    2011年8月10日 5:26
  • > 私の環境化では、教えて頂いたコードのtreeView.SelectItem()が利用できなかったため(存在しないメソッドの模様)

    私のソースをよくみたところ、SelectItemメソッドはSilverlightToolkitで定義されている拡張メソッドでした。
    アセンブリ System.Windows.Controls.Toolkit.dll 内の System.Windows.Controls.TreeViewExtensions 静的クラスで定義されていました。
    失礼しました。

    • 回答としてマーク femp 2011年8月10日 7:08
    2011年8月10日 6:35
  • 補足ありがとうございます。
    System.Windows.Controls.Toolkitアセンブリの参照を追加したら使えるようになりました。
    2011年8月10日 7:08