2012-05-16 3 views
1

.NET TreeView 컨트롤에서 파생 된 C# 클래스에서 here으로 트리 뷰 알림을 처리하는 방법은 무엇입니까? 파생 된 C# 사용자 정의 컨트롤의 Windows 처리 처리

나는 다음과 같은 예를 들어, 클릭 통지를 처리하기 위해 노력 :

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 컨트롤의 동작을 수정하려고 시도한 것은 처음이므로 무엇이 잘못되는지 전혀 모릅니다.

이러한 알림을 처리하는 올바른 방법입니까?

FYI : .NET TreeView 컨트롤에 클릭 이벤트가 있다는 것을 알고 있습니다. 이것은 단지 첫 번째 테스트 일뿐입니다. 나중에 TVS_EX_MULTISELECT 스타일을 사용하고 싶습니다. TVS_EX_MULTISELECT이 활성화되면 .NET TreeView 컨트롤이 AfterSelect 이벤트를 발생시키지 않으므로 나중에 TVN_SELCHANGEDTVN_ITEMCHANGED 알림의 동작을 조사하려고합니다.

답변

4

그렇게 간단하지 않습니다. MSDN article을 확인하면 NM_CLICK 알림이 WM_NOTIFY 메시지로 전달됩니다. 그리고 그것은 treeview의 부모으로 보내집니다. 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; 
    } 
} 

가 트 리뷰가 이미 모든이 작업을 수행주의, 즉 NodeMouseClick가, 클릭하고 MouseClick과 이벤트가 생성되는 방법을합니다. 이 작업을 수행하는 코드는 네이티브 컨트롤의 일부 쿼크 (quirks)에서도 작동하므로 사용하기 전에 꼭 필요합니다. 무슨 일이 일어나고 있는지 알고 싶다면 Reference Source를 검토하십시오.

+0

아니요, 부모 제어 장치로 보내고 내 대답을 확인하십시오 ;-) – 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 메시지로 수행됩니다. 다행히도 저자는 트리 뷰의 하위 클래스가 알림을 수신 할 수 있도록하는 리플렉션이라는 메커니즘도 포함했습니다. 메시지는 WM_NOTIFY으로 정확히 처리 할 수있는 &H2000 | WM_NOTIFY입니다.

또한 NM_CLICK 메시지 있지 않으며, 그러나이 통지는 통지 코드가 WM_NOTIFY 메시지 형태로 전송되는 NMHDR 구조

내측 랩.

+0

빠른 작업 코드/예제가 없습니다. 어쨌든, win32입니다, 우리가 그것을 실행하지 않으면 우리는 확신 할 수 없습니다, 그렇죠? ;-) – peenut

0

MSDN에 언급 된 중요한 두 가지가 있습니다. 1) msg.LPARAM은 NMHDR 구조체의 포인터이다 이 통지는 부모 컨트롤에 보낼 수 있습니다) 그래서 작업 코드 (콘솔 응용 프로그램으로 컴파일입니다

- 거기 메시지를 출력 할 것이다) :

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

편집 : 및하지 당연히/안전하지 않은 것으로 컴파일하는 것을 잊어 버리십시오.

관련 문제