10
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[WPF][MVVM] TreeViewItemの右クリックメニューからViewModelのCommandを実行する

Posted at

WPFのTreeViewの子要素を右クリックするとメニューを出して、そのアイテムを利用したコマンドを実装したかったんですが、やたらと実装が難航したので設定方法をメモ。

実装例

ContextMenu側XAML
<UserControl.Resources>
    <ContextMenu x:Key="SampleContextMenu">
        <MenuItem Header="右クリックメニューアイテム"
                  Command="{Binding
                        Path=PlacementTarget.Tag.Command,
                        RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"
                  CommandParameter="{Binding
                        Path=PlacementTarget.DataContext,
                        RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>
    </ContextMenu>
</UserControl.Resources>
TreeView側XAML
<TreeView ItemsSource="{Binding Path=...}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="Tag" Value="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}"/>
            <Setter Property="ContextMenu" Value="{Binding Source={StaticResource SampleContextMenu}}"/>
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <!-- 省略 -->
    </TreeView.ItemTemplate>
</TreeView>

やりたかったこと

  1. 右クリックメニューのクリックで、ViewModelに実装したCommandを実行する
  2. その際の引数として、右クリックしたTreeViewItemのデータを利用したい
  3. イベントハンドラは使わずに実現したい(コードビハインドに書くのは最後の手段)

内容解説

まず注意する必要があるのは、WPFのContextMenuはXAMLのVisualTreeの定義とは別管理?(※要調査)になるらしく、単純にViewModelのCommandはそのまま定義しても見えないということです。右クリックメニューを出したアイテムが見たい場合は PlacementTarget を利用する必要があるようです。

TreeViewの場合は、Templateの関係でDataContextが書き換わってしまっています。そのため2のTreeViewItemのデータはPlacementTargetのDataContextを利用すれば良いです。

ViewModelに定義しているCommandを使いたい場合はさらに上のDataContextを参照する必要があります。Templateの親を指定できる TemplatedParent はContextMenuからでは使えません。なので、TreeViewItemのTagプロパティに親のDataContextを事前にBindしておき、ContextMenuから PlacementTarget.Tag で参照できるようにします。

(ちなみにTagプロパティは任意のデータを格納する専用のプロパティのようです。)
FrameworkElement.Tag プロパティ (System.Windows)

これでTreeViewItemのContextMenuからViewModelのCommandを実行できるようになりました。
Templateを使用しているListViewでも同様のことが起きると思いますが、上記の実装で同様に対処できるかと思います。

参考

WPF ContextMenu woes: How do I set the DataContext of the ContextMenu? - Stack Overflow
WPF/XAML で右クリックメニューへの DataContext の引き回し - graphics.hatenablog.com

10
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?