Вопрос по c#, winapi, user-controls, treeview – Обработка уведомлений Windows в производном пользовательском элементе управления C #

1

Как я могу обработать любое из представленных уведомлений в виде дереваВот в классе C #, который является производным от элемента управления .NET TreeView?

Я пытался обработать уведомление о клике, например, так:

class ExtendedTreeView : TreeView
{
    private const Int32 NM_FIRST = (Int32)(0U - 0U);
    private const Int32 NM_CLICK = unchecked((Int32)((UInt32)NM_FIRST - 2U));

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == NM_CLICK)
        {
            MessageBox.Show("NM_CLICK");
        }
        base.WndProc(ref m);
    }
}

Но окно сообщения никогда не отображается. Это первый раз, когда я пытаюсь использовать Win32 API, чтобы изменить поведение элемента управления .NET, поэтому я понятия не имею, что идет не так.

Это правильный подход для обработки этих уведомлений?

К вашему сведению: я знаю, что элемент управления .NET TreeView имеет событие щелчка. Это всего лишь первый тест. Позже я хочу включитьTVS_EX_MULTISELECT стиль. Поскольку элемент управления .NET TreeView не запускаетAfterSelect события, когдаTVS_EX_MULTISELECT включен, я хочу исследовать поведениеTVN_SELCHANGED а такжеTVN_ITEMCHANGED уведомления позже.

Ваш Ответ

3   ответа
2

Уведомления отправляются родителю элемента управления:

Notifies the parent window of a tree-view control that the user has clicked the left mouse button within the control.

Это сделано сWM_NOITIFY сообщение. К счастью, авторы также включили механизм отражения, позволяющий подклассам древовидного представления получать уведомления также. Сообщение&H2000 | WM_NOTIFY который вы можете относиться именно такWM_NOTIFY.

Также обратите внимание, чтоNM_CLICK это не сообщение, а уведомление, заключенное вNMHDR состав

This notification code is sent in the form of a WM_NOTIFY message.

быстрее, но без хорошего рабочего кода / примера. в любом случае, это win32, мы не можем быть уверены, если не запустим его, верно? ;-)
0

Есть две важные вещи, которые упоминаются в MSDN: 1) msg.lparam - указатель на структуру NMHDR 2) уведомления отправляются на родительский контроль

Итак, рабочий код (скомпилировать как консольное приложение - он будет печатать там сообщения):

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class MyTreeView : TreeView
{
    public TreeView RealTreeView;
    public MyTreeView()
    {
        RealTreeView = new TreeView();
        RealTreeView.Dock = DockStyle.Fill;
        Controls.Add(RealTreeView);
    }
    enum WM
    {
        NOTIFY = 78
    }
    enum NM : uint
    {
        FIRST = 0,
        NM_CLICK = unchecked(FIRST - 2),
        NM_CUSTOMDRAW = unchecked(FIRST - 12),
        NM_DBLCLK = unchecked(FIRST - 3),
        NM_KILLFOCUS = unchecked(FIRST - 8),
        NM_RCLICK = unchecked(FIRST - 5),
        NM_RDBLCLK = unchecked(FIRST - 6),
        NM_RETURN = unchecked(FIRST - 4),
        NM_SETCURSOR = unchecked(FIRST - 17),
        NM_SETFOCUS = unchecked(FIRST - 7)
    }

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

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == (int)WM.NOTIFY)
        {
            uint code;
            unsafe
            {
                var nmhdr = (NMHDR*)m.LParam.ToPointer();
                code = nmhdr->code;
            }
            NM nmCode = (NM)code;
            Console.WriteLine("WM_NOTIFY " + nmCode);
        }
    }
}

public class MyGuiClass
{
    public static void Main()
    {
        Form f = new Form();
        var tv = new MyTreeView();
        tv.RealTreeView.Nodes.Add("zero").Nodes.Add("sub-zero");
        tv.RealTreeView.Nodes.Add("one");
        tv.RealTreeView.Nodes.Add("two");
        tv.RealTreeView.Nodes.Add("three");
        tv.Dock = DockStyle.Fill;
        f.Controls.Add(tv);
        Application.Run(f);
    }
}

Изменить: и не забудьте, конечно, скомпилировать с / unsafe.

4

Все не так просто. ПроверитьСтатья MSDNуведомление NM_CLICK доставляется как сообщение WM_NOTIFY. И это отправленоparent из дерева. В Winforms имеется вертикаль, которая возвращает его к исходному элементу управления, что позволяет обрабатывать сообщение классом, производным от TreeView, и настраивать обработку событий. Это делается путем добавления к сообщению 0x2000, значения WM_REFLECT в исходном коде Winforms.

Так что код должен выглядеть так:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class ExtendedTreeView : TreeView {
    protected override void WndProc(ref Message m) {
        if (m.Msg == WM_REFLECT + WM_NOFITY) {
            var notify = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
            if (notify.code == NM_CLICK) {
                MessageBox.Show("yada");
                m.Result = (IntPtr)1;
                return;
            }

        }
        base.WndProc(ref m);
    }
    private const int NM_FIRST = 0;
    private const int NM_CLICK = NM_FIRST - 2;
    private const int WM_REFLECT = 0x2000;
    private const int WM_NOFITY = 0x004e;

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

Помните, что TreeView уже делает все это, как генерируются события NodeMouseClick, Click и MouseClick. Код, который делает это, также работает с некоторыми причудами в родном элементе управления, поэтому убедитесь, что он вам действительно нужен, прежде чем использовать его. Просмотрите справочный источник, если вы хотите знать, что происходит.

@peenut - да, и родитель отправляет его обратно. Проверьте использование WM_REFLECT во фрагменте. Это чистая деталь реализации Winforms, но в остальном распространенная в библиотеках классов, которые обертывают API.
К вашему сведению след0x2000 в другом вопросеstackoverflow.com/questions/10637133/…
Нет, он отправлен на родительский контроль, проверьте мой ответ ;-)

Похожие вопросы