質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

1回答

11751閲覧

WPFでContextMenuの表示をさせたくない!

plue

総合スコア71

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2016/04/15 09:28

WPFで画面の作成を行っているのですが、ContextMenuの表示の設定に困っています。
やりたいのは以下のことです。

①GridにはContextMenuを表示する。
②Grid内のExpanderにはContextMenuを表示しない。
③Expander内のTreeViewItemにはContextMenuを表示する。

①と③は以下のソースにて、実現できたのですが、
②についてはなぜか①と同じContextMenuが表示されてしまいます。

ExpanderにContextMenuを表示させないようにするにはどうすればよいのでしょうか?
また、なぜGridと同じContextMenuが表示されてしまうのでしょうか?
お分かりになる方がいらっしゃいましたら、教えていただけないでしょうか?
よろしくお願い致します。

XAML

1 <Grid Margin="0,100,0,0"> 2 3 <!-- GridにはContexMenuを表示! --> 4 <Grid.Resources> 5 <ContextMenu x:Key="GridPopup"> 6 <MenuItem Header="Grid1..."/> 7 <MenuItem Header="Grid2..."/> 8 <MenuItem Header="Grid3..."/> 9 </ContextMenu> 10 </Grid.Resources> 11 <Grid.ContextMenu> 12 <ContextMenu ContextMenu="{StaticResource GridPopup}" /> 13 </Grid.ContextMenu> 14 15 <!-- ContextMenuを表示させたくない! --> 16 <Expander Header="expander"> 17 <TreeView> 18 <TreeView.Resources> 19 <ContextMenu x:Key="ItemPopup1"> 20 <MenuItem Header="New Scale..."/> 21 </ContextMenu> 22 <ContextMenu x:Key="ItemPopup2"> 23 <MenuItem Header="Remove Scale"/> 24 </ContextMenu> 25 </TreeView.Resources> 26 27 <!-- TreeViewItemにはContexMenuを表示! --> 28 <TreeViewItem Header="first" ContextMenu="{StaticResource ItemPopup1}" /> 29 <TreeViewItem Header="second" ContextMenu="{StaticResource ItemPopup2}" /> 30 </TreeView> 31 </Expander> 32 </Grid> 33

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ContextMenuはコントロールのMouseRightButtonUpイベントによって表示されます。
これはルーティングイベントと言われるもので、親要素から子要素にイベントが下っていくトンネルイベントと子要素から親要素に上がっていくバブルイベントの2種類があり(本当は直接ルーティングもあるけど割愛)、WPFは各種イベントに該当する操作をキャッチするとトンネル→バブルの順で対応するコントロールのイベントをハンドルします。
例として今回の場合はまずマウスの右ボタンが離れると、トンネルイベントであるPreviewMouseRightButtonUpがGrid→Expander→TreeView→TreeViewItemの順でハンドルされます。その後、バブルイベントであるMouseRightButtonUpがTreeViewItem→TreeView→Expander→Gridの順でハンドルされます。
Expanderクリック時にGridのContextMenuが表示されるのはExpanderにはMouseRightButtonUpで特に何かをするように設定されていないので、素通りしてそのままGridまでMouseRightButtonUpイベントが上がっているからです。

ExpanderにGridのContextMenuを表示させない方法としては幾つかあります。
①Expanderには表示させたくないContextMenuを表示させたい領域にGridを設定して、ExpanderをGridの子要素から外す。基本的にはこれが一般的。

XAML

1<Grid> 2 <Grid.RowDefinitions> 3 <RowDefinition/> 4 <RowDefinition/> 5 </Grid.RowDefinitions> 6 <!-- このGridにはContextMenuが表示される--> 7 <Grid 8 Grid.Row="0" 9 Background="Transparent"> 10 <Grid.ContextMenu> 11 <ContextMenu> 12 <MenuItem Header="Grid1..."/> 13 <MenuItem Header="Grid2..."/> 14 <MenuItem Header="Grid3..."/> 15 </ContextMenu> 16 </Grid.ContextMenu> 17 </Grid> 18 <!-- ContextMenuを設定したGridの子要素ではないので表示されない--> 19 <Expander 20 Grid.Row="1" 21 Header="expander"> 22 <TreeView 23 IsHitTestVisible="True"> 24 <TreeView.Resources> 25 <ContextMenu x:Key="ItemPopup1"> 26 <MenuItem Header="New Scale..."/> 27 </ContextMenu> 28 <ContextMenu x:Key="ItemPopup2"> 29 <MenuItem Header="Remove Scale"/> 30 </ContextMenu> 31 </TreeView.Resources> 32 33 <!-- TreeViewItemにはContexMenuを表示!--> 34 <TreeViewItem Header="first" ContextMenu="{StaticResource ItemPopup1}" /> 35 <TreeViewItem Header="second" ContextMenu="{StaticResource ItemPopup2}" /> 36 </TreeView> 37 </Expander> 38</Grid>

ExpanderをどうしてもGridの子要素から外せない場合は、
②ExpanderのMouseRightButtonUpにイベントを設定してGridにMouseRightButtonUpイベントが行かないようにする。

XAML

1<Grid> 2 <!-- GridにはContexMenuを表示! --> 3 <Grid.ContextMenu> 4 <ContextMenu> 5 <MenuItem Header="Grid1..."/> 6 <MenuItem Header="Grid2..."/> 7 <MenuItem Header="Grid3..."/> 8 </ContextMenu> 9 </Grid.ContextMenu> 10 11 <!-- ContextMenuを表示させたくない! --> 12 <Expander 13 MouseRightButtonUp="Expander_MouseRightButtonDown" 14 Header="expander"> 15 <TreeView> 16 <TreeView.Resources> 17 <ContextMenu x:Key="ItemPopup1"> 18 <MenuItem Header="New Scale..."/> 19 </ContextMenu> 20 <ContextMenu x:Key="ItemPopup2"> 21 <MenuItem Header="Remove Scale"/> 22 </ContextMenu> 23 </TreeView.Resources> 24 25 <!-- TreeViewItemにはContexMenuを表示! --> 26 <TreeViewItem Header="first" ContextMenu="{StaticResource ItemPopup1}" /> 27 <TreeViewItem Header="second" ContextMenu="{StaticResource ItemPopup2}" /> 28 </TreeView> 29 </Expander> 30</Grid>

コードビハインド

C#

1private void Expander_MouseRightButtonDown(object sender, MouseButtonEventArgs e) 2{ 3 e.Handled = true; 4}

このe.Handledにtrueを入れるとそのイベントを設定したコントロール以降のコントロールにイベントがルーティングされません。トンネルイベントなら全ての子要素、バブルイベントなら全ての親要素の該当イベントを握りつぶします。TreeViewItemを右クリックした時にGridのContextMenuが表示されずにTreeViewItemのContextMenuのみ表示されるのはTreeViewItemがMouseRightButtonUpイベントを握りつぶしているからです。

コードビハインドなんて使いたくないというのであれば一番簡単なのは、
③Expanderに空のContextMenuを入れる。

XAML

1<Grid> 2 <!-- GridにはContexMenuを表示! --> 3 <Grid.ContextMenu> 4 <ContextMenu> 5 <MenuItem Header="Grid1..."/> 6 <MenuItem Header="Grid2..."/> 7 <MenuItem Header="Grid3..."/> 8 </ContextMenu> 9 </Grid.ContextMenu> 10 11 <!-- ContextMenuを表示させたくない! --> 12 <Expander 13 Header="expander"> 14 <Expander.ContextMenu> 15 <ContextMenu/> 16 </Expander.ContextMenu> 17 <TreeView> 18 <TreeView.Resources> 19 <ContextMenu x:Key="ItemPopup1"> 20 <MenuItem Header="New Scale..."/> 21 </ContextMenu> 22 <ContextMenu x:Key="ItemPopup2"> 23 <MenuItem Header="Remove Scale"/> 24 </ContextMenu> 25 </TreeView.Resources> 26 27 <!-- TreeViewItemにはContexMenuを表示! --> 28 <TreeViewItem Header="first" ContextMenu="{StaticResource ItemPopup1}" /> 29 <TreeViewItem Header="second" ContextMenu="{StaticResource ItemPopup2}" /> 30 </TreeView> 31 </Expander> 32</Grid>

私が思いつくのはこれくらい。

これ以外だとExpanderのTemplateいじるとかカスタムコントロール作ってHitTestのロジックいじるとかめんどくさいことくらいしか思いつかないからここでは書きません。

投稿2016/04/16 13:53

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

plue

2016/04/18 06:31

回答ありがとうございます。 トンネル・バブルイベントについては初めて知りました。 とても勉強になりました。 今回、ExpanderをどうしてもGridの子要素から外せないため、 ②を試させていただいたのですが、 ・Grid   → ContextMenuを表示できた ・Expander → ContextMenuを非表示にできた ・TreeViewItem → ContextMenuが表示されない となり、TreeViewItemだけがうまくいきません。 私のバブルイベントの理解では、TreeViewItemのを右クリックしたとき、 バブルイベントはExpanderで握りつぶされてしまい、TreeViewItemのContextMenuのみが表示されると思っているのですが、間違っているのでしょうか。 tx4jさんのマシン上ではTreeViewItemにはContextMenuが表示されたのでしょうか? 追加の質問で申し訳ないのですかご教示いただければと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問