[C# WPF] システムメニューが開かれたタイミングでなにかしたい

2019年4月18日

メニューが開かれたときには設定を解除しないといけない案件がありました。
メインメニューとコンテキストメニューはContextMenuOpendのイベントハンドラを使えば対応できたのですが、システムメニューどうするんだ?ということで調べた結果です。
WPFだけではシステムメニューが開かれるタイミングを取得できなかったので、WndProcをフックすることになりました。

スポンサーリンク

サンプルコード

最小構成のサンプルです。
システムメニューが開かれるとデバッグ出力します。
メインメニューとコンテキストメニューは、メッセージが飛んでこないことの確認用です。

<window
  x:class="Sample_WndProc.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:Sample_WndProc"
  mc:ignorable="d" title="MainWindow" height="350" width="525"
  loaded="Window_Loaded">

    <dockpanel>
        <menu dockpanel.dock="Top" verticalalignment="Top">
            <menuitem header="File">
                <menuitem header="File 1"/>
                <menuitem header="File 2"/>
                <menuitem header="File 3"/>
            </menuitem>
        </menu>

    <window.contextmenu>
        <contextmenu>
            <menuitem header="menu 1"/>
            <menuitem header="menu 2"/>
            <menuitem header="menu 3"/>
        </contextmenu>
    </window.contextmenu>

</window>
using System;
using System.Windows;
using System.Windows.Interop;

namespace Sample_WndProc
{
    /// 
    /// MainWindow.xaml の相互作用ロジック
    /// 
    public partial class MainWindow : Window
    {
        private HwndSource _hwndSource = null;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _hwndSource = PresentationSource.FromVisual(this) as HwndSource;
            if (_hwndSource != null)
            {
                _hwndSource.AddHook(WndProc);
            }
        }

        private enum WindowMessage : uint
        {
            WM_INITMENU = 0x0116
        }

        private IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == (int)WindowMessage.WM_INITMENU)
            {
                System.Diagnostics.Debug.Print("init menu");
            }

            return IntPtr.Zero;
        }
    }
}

メインメニューやコンテキストメニューを開くときにも呼ばれそうだったのですが、呼ばれなかったのでWM_INITMENUのメッセージを使用しています(mfcでは呼ばれたような気が。

おしまい。

スポンサーリンク

C#,WPFC#,WPF

Posted by peliphilo