[C#]WPFでヘッダー右クリック時のメニューを変更する

# 右クリック時のメニュー（コンテキストメニュー）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47053/78097908-13b9-031f-d4bd-99537fe37707.png)

こういうメニューのことをコンテキストメニューと言います。  
今回は自作アプリのヘッダー部を右クリックしたときのメニューを変更する方法を記載します。

上記画面のメニューに追加するパターンと完全に自作のメニューを表示するパターンの２つを作ります。

- パターン１
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47053/61190525-da0d-4254-6f0b-0be0a20a7a8b.png)

- パターン２
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47053/3ed195b5-8485-fdd6-ad6c-d301d762227c.png)

こういう感じになります。  

# 既存のコンテキストメニューに要素を追記する方法

Win32APIを使います。
まずはWin32API使えるようにし、使用する関数を宣言します。

```C#
        [DllImport("user32.dll")]
        private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
        [DllImport("user32.dll")]
        private static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, Int32 wFlags, Int32 wIDNewItem,
                string lpNewItem);
``` 

次に使用する定数を宣言します。

```C#
        private readonly Int32 MF_BYPOSITION = 0x400;
        private readonly Int32 MF_SEPARATOR = 0x800;
        private const Int32 ITEMONEID = 1000;
        private const Int32 ITEMTWOID = 1001;

        private readonly Int32 WM_SYSCOMMAND = 0x112;
```

ロード時に処理を書きます。

```C#
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            IntPtr windowhandle = new WindowInteropHelper(this).Handle;
            HwndSource hwndSource = HwndSource.FromHwnd(windowhandle);
            IntPtr systemMenuHandle = GetSystemMenu(windowhandle, false);
            InsertMenu(systemMenuHandle,5, MF_BYPOSITION| MF_SEPARATOR, 0, string.Empty);
            InsertMenu(systemMenuHandle,6, MF_BYPOSITION, ITEMONEID, "Item 1");
            InsertMenu(systemMenuHandle,7, MF_BYPOSITION, ITEMTWOID, "Item 2");

            hwndSource.AddHook(new HwndSourceHook(WndProc));
        }

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
        {
            if(msg == WM_SYSCOMMAND)
            {
                switch(wparam.ToInt32())
                {
                    case ITEMONEID:
                    {
                        MessageBox.Show("Item 1 was clicked");
                        handled = true;
                        break;
                    }
                    case ITEMTWOID:
                    {
                        MessageBox.Show("Item 2 was clicked");
                        handled = true;
                        break;
                    }
                }
            }

            return IntPtr.Zero;
        }
```

# 自作のコンテキストメニューを表示する方法

xaml側にリソースを定義します。
とりあえず、Item1の時だけ実装。

```
    <Window.Resources>
        <ContextMenu x:Key="contextMenu" >
            <MenuItem Header="Item 1" Click="MenuItem_OnClick"></MenuItem>
            <MenuItem Header="Item 2"></MenuItem>
            <MenuItem Header="Item 3"></MenuItem>
        </ContextMenu>
    </Window.Resources>
```

コードビハインド側

```C#
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            IntPtr windowhandle = new WindowInteropHelper(this).Handle;
            HwndSource hwndSource = HwndSource.FromHwnd(windowhandle);

            hwndSource.AddHook(new HwndSourceHook(WndProc));
        }
        private void MenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            var item = sender as MenuItem;
            MessageBox.Show(item.Header.ToString());
        }
        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
        {
            if(msg == 0xa4)
            {
                ShowContextMenu();
                handled = true;
            }
            return IntPtr.Zero;
        }

        private void ShowContextMenu()
        {
            var contextMenu = Resources["contextMenu"] as ContextMenu;
            contextMenu.IsOpen = true;
        }
```

ソースコード  
https://github.com/KoMMet/WpfContext