2012-05-16 75 views
1

如何處理從.NET TreeView控件派生的C#類中列出的任何樹視圖通知here在派生的C#用戶控件中處理Windows通知

我試圖處理click通知,例如,像這樣:

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樣式。由於在啓用TVS_EX_MULTISELECT時,.NET TreeView控件不會觸發任何AfterSelect事件,因此我想稍後調查TVN_SELCHANGEDTVN_ITEMCHANGED通知的行爲。

回答

4

它並不那麼簡單。檢查MSDN article,NM_CLICK通知作爲WM_NOTIFY消息提供。它被髮送到樹視圖的。 Winforms已將管道回覆到原始控件,以允許通過從TreeView派生的類來處理消息並自定義事件處理。這是通過向Winforms源代碼中的WM_REFLECT值添加0x2000來完成的。

因此,代碼應該是這樣的:

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,點擊並獲取生成鼠標點擊事件。這樣做的代碼也適用於本地控制中的一些怪癖,所以在提交之前確保你確實需要這個。如果您想知道發生了什麼,請查看參考源。

+0

nope,它發送給家長控制,檢查我的答案;-) – peenut

+0

@peenut - 是的,父母發回它。在片段中檢查WM_REFLECT的使用。它是一個純Winforms實現細節,但在包裝api的類庫中很常見。 –

+0

FYI在另一個問題中'0x2000'的跟蹤http://stackoverflow.com/questions/10637133/wm-reflect-notify-vs-wm-notify/10637914#10637914 –

2

通知被髮送到控件的父:

通知樹視圖控制的父窗口用戶已經點擊了控制內的鼠標左鍵。

這是通過WM_NOITIFY消息完成的。幸運的是,作者還包含一個名爲reflection的機制,允許treeview的子類也接收通知。該消息是&H2000 | WM_NOTIFY,您可以完全對待WM_NOTIFY

還要注意的是NM_CLICK不是消息,但包裹一個NMHDR結構

該通知代碼在WM_NOTIFY消息的形式發送內的通知。

+0

更快,但沒有很好的工作代碼/示例。無論如何,這是win32,除非我們運行它,否則我們無法確定,對吧? ;-) – peenut

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); 
    } 
} 

編輯:也不要當然忘記編譯/不安全。

相關問題