如何处理从.NET TreeView控件派生的C#类中列出的here中的任何树视图通知?
我尝试处理点击通知,例如:
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控件有一个click事件。这只是第一次测试。后来我想启用TVS_EX_MULTISELECT
样式。由于.NET TreeView控件在启用AfterSelect
时不会触发任何TVS_EX_MULTISELECT
事件,因此我想稍后调查TVN_SELCHANGED
和TVN_ITEMCHANGED
通知的行为。
答案 0 :(得分:4)
不是那么简单。检查MSDN article,NM_CLICK通知作为WM_NOTIFY消息传递。并将其发送到树视图的父。 Winforms有适当的管道将它回显给原始控件,以允许消息由派生自TreeView的类处理并自定义事件处理。这是通过在消息中添加0x2000,Winforms源代码中WM_REFLECT的值来完成的。
所以代码应如下所示:
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事件的生成方式。执行此操作的代码也适用于本机控件中的一些怪癖,因此请确保在提交使用它之前确实需要它。如果您想知道发生了什么,请查看参考源。
答案 1 :(得分:2)
通知发送给控件的父级:
通知树视图控件的父窗口,用户在控件中单击了鼠标左键。
这是通过WM_NOITIFY
消息完成的。幸运的是,作者还包括一种称为反射的机制,允许树视图的子类也接收通知。邮件为&H2000 | WM_NOTIFY
,您可以将其视为WM_NOTIFY
。
另请注意,NM_CLICK
不是消息,而是包含在NMHDR
结构中的通知
此通知代码以WM_NOTIFY消息的形式发送。
答案 2 :(得分: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编译。