0

TreeViewからTVN_SELCHANGINGメッセージをキャッチしようとしています。BeforeSelectイベントもあることは知っていますが、メッセージをキャッチできない理由を理解したいと思います…</ p>

私はmsdnでTVN_SELCHANG(ED)(ING)を読みました。LParamはNMTREEVIEW構造体へのポインターです。また、コードはWM_NOTIFYメッセージの形式で送信されます。

だから私はそれを実装しようとしました:( これは私を助けました)

public partial class TreeviewEx : TreeView
{
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct TVITEM
    {
        public uint mask;
        public IntPtr hItem;
        public uint state;
        public uint stateMask;
        public IntPtr pszText;
        public int cchTextMax;
        public int iImage;
        public int iSelectedImage;
        public int cChildren;
        public IntPtr lParam;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct NMHDR
    {
        public IntPtr hwndFrom;
        public IntPtr idFrom;
        public int code;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct NMTREEVIEW
    {
        public NMHDR hdr;
        public int action;
        public TVITEM itemOld;
        public TVITEM itemNew;
        public POINT ptDrag;
    }

    private const int TVN_FIRST = -400;
    private const int TVN_SELCHANGINGA = (TVN_FIRST - 1);
    private const int TVN_SELCHANGINGW = (TVN_FIRST - 50);
    private const int TVN_SELCHANGEDA = (TVN_FIRST - 2);
    private const int TVN_SELCHANGEDW = (TVN_FIRST - 51);

    private const int WM_NOTIFY = 0x004e;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_NOTIFY)
        {
            var notify = (NMTREEVIEW)Marshal.PtrToStructure(m.LParam, typeof(NMTREEVIEW));
            if (notify.action == TVN_SELCHANGINGA)
            {
                MessageBox.Show("changing");
            }
        }
        base.WndProc(ref m);
    }

私はすべてのアクションを試しましたが、どれも機能していないようです。私は何が間違っているのですか?

4

1 に答える 1

2

そうです、これは機能しません。その背後にある多くの歴史、ネイティブWindowsコントロールはCプログラムで使用するように設計されました。Petzoldの「ProgrammingWindows」スタイルのコーディングを使用して、ウィンドウプロシージャにウィンドウのカスタムロジックを配置します。そして、TreeViewのようなコントロールをそのまま使用しました。したがって、これらのコントロールは通知メッセージをウィンドウに送信します。それはあなたがあなたのコードを置くところだからです。

これは、最新のGUIコードの記述方法とはあまり互換性がありません。特に、コントロールを継承して新しい動作を与えるという概念。TreeViewExクラスで行ったように。あなたは本当に最初にあなた自身のクラスでこれらの通知を受け取りたいです。したがって、OnBeforeSelect()を使用して興味深いことを実行し、コントロールの動作をカスタマイズできます。このメッセージを親に送信することはかなり大きな問題であるため、コントロールは親の実装を認識してはなりません。

Winformsはこの問題を修正し、親ウィンドウからのメッセージを元のウィンドウに反映します。メッセージを変更する必要があります。これにより、メッセージが反映されたメッセージであることが完全に明確になります。これは、メッセージ番号WM_REFLECTに定数を追加することで実行されます。この値は、0x2000にハードコーディングできます。したがって、次のように修正します。

private const int WM_REFLECT = 0x2000;

protected override void WndProc(ref Message m) {
    if (m.Msg == WM_REFLECT + WM_NOTIFY) {
        var nmhdr = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
        if (nmhdr.code == TVN_SELCHANGINGW) {
           var notify = (NMTREEVIEW)Marshal.PtrToStructure(m.LParam, typeof(NMTREEVIEW));
           // etc..
        }
    }
    base.WndProc(ref m);
}
于 2013-01-09T18:26:38.413 に答える