Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This example shows how to subclass a TreeView control to create a NodeMouseClick event, which is not available in the .NET Compact Framework.
The form displays the subclassed TreeView control and information about a clicked node. It shows the a node's text and the x and y coordinates of where the TreeView control was clicked, which changes as you click in different places on a node.
This example program is described in detail in Subclassing Controls with a Managed Window Procedure.
To subclass a TreeView control to create a NodeMouseClick event
In Microsoft Visual Studio 2005, create a Smart Device Pocket PC project.
Add the
Win32
helper class to your project. This code is available in How to: Use a Helper Class for Platform Invokes.Add the
WinProcHooker
class to your project. This code is available in How to: Use a Class for Hooking Windows Procedures.Add the
TreeViewBonus
class to your project.// Extends the standard TreeView control to add an implementation // of the NodeMouseClick event. public class TreeViewBonus : TreeView { // The original parent of this control. Control prevParent = null; // Creates a new instance of the derived TreeView control public TreeViewBonus() { } // Called when the control's parent is changed. Here we hook into that // parent's WndProc and spy on the WM_NOTIFY message. When the parent // changes, we unhook the old parent's WndProc and hook into the new one. protected override void OnParentChanged(EventArgs e) { // unhook the old parent if (this.prevParent != null) { WndProcHooker.UnhookWndProc(prevParent, Win32.WM_NOTIFY); } // update the previous parent prevParent = this.Parent; // hook up the new parent if (this.Parent != null) { WndProcHooker.HookWndProc(this.Parent, new WndProcHooker.WndProcCallback(this.WM_Notify_Handler), Win32.WM_NOTIFY); } base.OnParentChanged(e); } // Occurs when the user clicks a TreeNode with the mouse. public event TreeNodeMouseClickEventHandler NodeMouseClick; // Occurs when the mouse pointer is over the control and a mouse button is clicked. protected void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) { if (NodeMouseClick != null) NodeMouseClick(this, e); } // The method that gets called when a WM_NOTIFY message is received by the // TreeView's parent. // hwnd - The handle of the window that received the message // msg - The message received // wParam - The wParam arguments for the message // lParam - The lParam arguments for the message // handled - Set to true to indicate that this message was handled // Returns an appropriate return code for the message handled int WM_Notify_Handler( IntPtr hwnd, uint msg, uint wParam, int lParam, ref bool handled) { Win32.NMHDR nmHdr = new Win32.NMHDR(); System.Runtime.InteropServices.Marshal.PtrToStructure((IntPtr)lParam, nmHdr); switch (nmHdr.code) { case Win32.NM_RCLICK: case Win32.NM_CLICK: // get the cursor coordinates on the client Point msgPos = Win32.LParamToPoint((int)Win32.GetMessagePos()); msgPos = this.PointToClient(msgPos); // check to see if the click was on an item Win32.TVHITTESTINFO hti = new Win32.TVHITTESTINFO(); hti.pt.X = msgPos.X; hti.pt.Y = msgPos.Y; int hitem = Win32.SendMessage(this.Handle, Win32.TVM_HITTEST, 0, ref hti); uint htMask = ( Win32.TVHT_ONITEMICON | Win32.TVHT_ONITEMLABEL | Win32.TVHT_ONITEMINDENT | Win32.TVHT_ONITEMBUTTON | Win32.TVHT_ONITEMRIGHT | Win32.TVHT_ONITEMSTATEICON); if ((hti.flags & htMask) != 0) { bool leftButton = (nmHdr.code == Win32.NM_CLICK); RaiseNodeMouseClickEvent(hti.hItem, leftButton ? MouseButtons.Left : MouseButtons.Right, msgPos); return 0; } break; default: break; } return 0; } // Raises the TreeNodeMouseClick event for the TreeNode with the specified handle. // hNode - The handle of the node for which the event is raised // button - The [mouse] buttons that were pressed to raise the event // coords - The [client] cursor coordinates at the time of the event void RaiseNodeMouseClickEvent(IntPtr hNode, MouseButtons button, Point coords) { TreeNode tn = FindTreeNodeFromHandle(this.Nodes, hNode); TreeNodeMouseClickEventArgs e = new TreeNodeMouseClickEventArgs( tn, button, 1, coords.X, coords.Y); OnNodeMouseClick(e); } // Finds a TreeNode in the provided TreeNodeCollection that has the handle specified. // Warning: recursion! // tnc - The TreeNodeCollection to search // handle - The handle of the TreeNode to find in the collection // Returns tThe TreeNode if found; null otherwise TreeNode FindTreeNodeFromHandle(TreeNodeCollection tnc, IntPtr handle) { foreach (TreeNode tn in tnc) { if (tn.Handle == handle) return tn; // we couldn't have clicked on a child of this node if this node // is not expanded! if (tn.IsExpanded) { TreeNode tn2 = FindTreeNodeFromHandle(tn.Nodes, handle); if (tn2 != null) return tn2; } } return null; } }
Add the
TreeNodeMouseClickEventArgs
class to your project.// Provides data for the System.Windows.Forms.TreeView.NodeMouseClick event public class TreeNodeMouseClickEventArgs : MouseEventArgs { // Initializes a new instance of the TreeNodeMouseClickEventArgs class. // node - The node that was clicked // button - One of the System.Windows.Forms.MouseButtons members // clicks - The number of clicks that occurred // x - The x-coordinate where the click occurred // y - The y-coordinate where the click occurred public TreeNodeMouseClickEventArgs(TreeNode node, MouseButtons button, int clicks, int x, int y) : base(button, clicks, x, y, 0) { nodeValue = node; } // // Gets the node that was clicked. // public TreeNode Node { get { return nodeValue; } set { nodeValue = value; } } TreeNode nodeValue; public override string ToString() { return string.Format( "TreeNodeMouseClickEventArgs\r\n\tNode: {0}\r\n\tButton: {1}\r\n\tX: {2}\r\n\tY: {3}", nodeValue.Text, Button.ToString(), X, Y); } }
Declare a form variable named
treeViewB
of typeTreeViewBonus
.private TreeViewBonus treeViewB;
Add the following code to the constructor of the
Form1
class, which should follow the call toInitializeComponent
. This code also adds a range of tree nodes and arranges their hierarchy.InitializeComponent(); this.treeViewB = new TreeViewBonus(); this.treeViewB.NodeMouseClick += new TreeNodeMouseClickEventHandler(this.tv_NodeMouseClicked); this.treeViewB.Location = new System.Drawing.Point(18, 16); this.treeViewB.Size = new System.Drawing.Size(205, 144); this.treeViewB.Name = "treeViewB"; // Set up the tree nodes. System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Node0"); System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Node2"); System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("Node3"); System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("Node6"); System.Windows.Forms.TreeNode treeNode5 = new System.Windows.Forms.TreeNode("Node7"); System.Windows.Forms.TreeNode treeNode6 = new System.Windows.Forms.TreeNode("Node8"); System.Windows.Forms.TreeNode treeNode7 = new System.Windows.Forms.TreeNode("Node4"); System.Windows.Forms.TreeNode treeNode8 = new System.Windows.Forms.TreeNode("Node1"); System.Windows.Forms.TreeNode treeNode9 = new System.Windows.Forms.TreeNode("Node5"); System.Windows.Forms.TreeNode treeNode10 = new System.Windows.Forms.TreeNode("Node9"); System.Windows.Forms.TreeNode treeNode11 = new System.Windows.Forms.TreeNode("Node10"); System.Windows.Forms.TreeNode treeNode12 = new System.Windows.Forms.TreeNode("Node11"); treeNode2.Text = "Node2"; treeNode4.Text = "Node6"; treeNode5.Text = "Node7"; treeNode6.Text = "Node8"; treeNode3.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { treeNode4, treeNode5, treeNode6}); treeNode3.Text = "Node3"; treeNode7.Text = "Node4"; treeNode1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { treeNode2, treeNode3, treeNode7}); treeNode1.Text = "Node0"; treeNode12.Text = "Node11"; treeNode11.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { treeNode12}); treeNode11.Text = "Node10"; treeNode10.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { treeNode11}); treeNode10.Text = "Node9"; treeNode9.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { treeNode10}); treeNode9.Text = "Node5"; treeNode8.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { treeNode9}); treeNode8.Text = "Node1"; this.treeViewB.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { treeNode1, treeNode8}); this.Controls.Add(treeViewB);
Add the delegate and the event-handling method for the derived
NodeMouseClick
event to theForm1
class.// Delegate represents the method that will handle // the NodeMouseClick event of a TreeView. // Parameters: // sender - The source of the event. // e - A TreeNodeMouseClickEventArgs that contains the event data. public delegate void TreeNodeMouseClickEventHandler(object sender, TreeNodeMouseClickEventArgs e); private void tv_NodeMouseClicked(object sender, TreeNodeMouseClickEventArgs e) { // Show the current node and the coordinates // in TreeView control where it was clicked. // This is just some of the information you // can obtain from TreeNodeMouseClickEventArgs. // Use a StringBuilder for efficient // use of device resources. StringBuilder sb = new StringBuilder(); sb.Append(e.Node.Text + " "); sb.Append("X: " + e.X.ToString() + ", "); sb.Append("Y: " + e.Y.ToString()); label1.Text = sb.ToString(); }
Compile and run the application.
See Also
Tasks
How to: Use a Class for Hooking Windows Procedures
How to: Use a Helper Class for Platform Invokes
How to: Subclass a TreeView by Using Native Callbacks
How to: Display a Gradient Fill
Concepts
.NET Compact Framework How-To Topics