WPF、右クリックメニューの表示、非表示切り替えはnullとIsOpen = trueでできた
ContextMenuOpeningイベントのときにnull指定で非表示にできるけど、また表示したくなったときにContextMenuを指定しても一回のクリックでは表示されない!そんなときは、IsOpen = trueで強制表示
これじゃない結果
マウスカーソルに赤丸表示が右クリックした印
期待する動作はRect1か2を右クリック時は右クリックメニューを開いて、それ以外の場所の右クリックでは開かない、なんだけどなんか違う
Rect以外を右クリックしたあとにRectを右クリックしても1回のクリックではメニューが開かなくて2回クリックすると開く動作になっている
結果1
これが求めていた動作、Rect以外のクリック後でも1回の右クリックでメニューが開いている
結果2
これは蛇足
Rect1と2を右クリックしたときは、それぞれ専用の右クリックメニューを開く
それ以外の場所を右クリックしたときは開かない
環境
- Windows 10 Home バージョン 21H2
- Visual Studio Community 2022 Version 17.5.3
- WPF
- C#
- .NET 6.0
コード
デザイナー画面
MainWindow.xaml
<Window x:Class="_20230408_ContextMemu.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:_20230408_ContextMemu" mc:Ignorable="d" Title="MainWindow" Height="150" Width="400"> <Grid> <UniformGrid Rows="1" Margin="70,30"> <DockPanel> <TextBlock Text="Rect1" DockPanel.Dock="Top"/> <Rectangle x:Name="MyRect1" Fill="BlueViolet"/> </DockPanel> <DockPanel> <TextBlock Text="Rect2" DockPanel.Dock="Top"/> <Rectangle x:Name="MyRect2" Fill="Gold"/> </DockPanel> <DockPanel> <TextBlock Text="その他要素" DockPanel.Dock="Top"/> <Rectangle Fill="Gray"/> </DockPanel> </UniformGrid> </Grid> </Window>
MainWindow.xaml.cs
using System.Windows; using System.Windows.Controls; //方法: ContextMenuOpening イベントを処理する - WPF .NET Framework | Microsoft Learn //https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/advanced/how-to-handle-the-contextmenuopening-event //右クリックメニュー(ContextMenu)の表示、非表示テスト namespace _20230408_ContextMemu { public partial class MainWindow : Window { private ContextMenu MyContextMenu1; private ContextMenu MyContextMenu2; public MainWindow() { InitializeComponent(); Top = 300; Left = 300; MyContextMenu1 = new(); MyContextMenu1.Items.Add(new MenuItem() { Header = "ランボー怒りの" }); MyContextMenu1.Items.Add(new MenuItem() { Header = "右クリック" }); MyContextMenu2 = new(); MyContextMenu2.Items.Add(new MenuItem() { Header = "Rect2専用" }); MyContextMenu2.Items.Add(new MenuItem() { Header = "暮らし安心" }); MyContextMenu2.Items.Add(new MenuItem() { Header = "ガウシアン" }); //右クリックメニュー開くときの動作 //これじゃない //ContextMenuOpening += MainWindow_ContextMenuOpening; //結果1 ContextMenuOpening += MainWindow_ContextMenuOpening1; //結果2 //ContextMenuOpening += MainWindow_ContextMenuOpening2; } //MyRectの1か2以外を右クリックした直後だと //MyRectの1か2を右クリックしてもメニューが表示されない //もう一度右クリックで表示される private void MainWindow_ContextMenuOpening(object sender, ContextMenuEventArgs e) { if (e.Source == MyRect1 || e.Source == MyRect2) { ContextMenu = MyContextMenu1; } else { ContextMenu = null; } } //これなら一回で表示される private void MainWindow_ContextMenuOpening1(object sender, ContextMenuEventArgs e) { if (e.Source == MyRect1 || e.Source == MyRect2) { //nullだった場合は表示したいメニューを指定後に強制表示 if (ContextMenu == null) { ContextMenu = MyContextMenu1; ContextMenu.IsOpen = true; } } else ContextMenu = null; } //MainWindow_ContextMenuOpening1を改変 //MyRect1か2なら、それぞれの右クリックメニューを表示する、それ以外は表示しない private void MainWindow_ContextMenuOpening2(object sender, ContextMenuEventArgs e) { bool flag = false; if (ContextMenu == null) { flag = true; } if (e.Source == MyRect1) { ContextMenu = MyContextMenu1; if (flag) { ContextMenu.IsOpen = true; } } else if (e.Source == MyRect2) { ContextMenu = MyContextMenu2; if (flag) { ContextMenu.IsOpen = true; } } else { ContextMenu = null; } } } }
あらかじめ右クリックメニューを用意しておいて、右クリックメニューを開くタイミングの、ContextMenuOpeningイベント時にメニューを入れ替える
これじゃない動作と結果1と2の切り替えは手動
結果1はnullチェックして、ContextMenu.IsOpen = true;
参照したところ
learn.microsoft.com
読んでもわからんけど、nullチェックとContextMenu.IsOpen = true;が関係あるっぽいのがわかった
なので、今回のもあっているかわからん、こう書いたら期待する動作になっただけ
感想
今回のテストのように特定のRectangleだけに表示したいだけなら、そのRectangle自体のContextMenuに付ければいいけどねえ
そうじゃないときもあって
範囲指定Thumbの右クリックメニュー
これは範囲指定ThumbのContextMenuに付けている
それ以外のThumbの右クリックメニュー
これも最初はThumb自体に付けようとしてたけど、ファイル保存のメソッドはMainWindowに書いたから、MainWindowのContextMenuに付けたほうが自然かなあとか
そもそもMainWindowにファイル保存のメソッドを書かないほうがいいのかとか、こうアプリの設計みたいなのは難しいねえ、どこに何を置くとかなんの機能をもたせるのかどんなクラスを作るのかとか
関連記事
次回は1週間後
gogowaten.hatenablog.com
前回のWPF記事は1ヶ月前
gogowaten.hatenablog.com