private unsafe void WmNotify(ref Message m) { NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR *)m.LParam; // Custom draw code is handled separately. // if ((nmhdr->code == NativeMethods.NM_CUSTOMDRAW)) { CustomDraw(ref m); } else { NativeMethods.NMTREEVIEW* nmtv = (NativeMethods.NMTREEVIEW*)m.LParam; switch (nmtv->nmhdr.code) { case NativeMethods.TVN_ITEMEXPANDINGA: case NativeMethods.TVN_ITEMEXPANDINGW: m.Result = TvnExpanding(nmtv); break; case NativeMethods.TVN_ITEMEXPANDEDA: case NativeMethods.TVN_ITEMEXPANDEDW: TvnExpanded(nmtv); break; case NativeMethods.TVN_SELCHANGINGA: case NativeMethods.TVN_SELCHANGINGW: m.Result = TvnSelecting(nmtv); break; case NativeMethods.TVN_SELCHANGEDA: case NativeMethods.TVN_SELCHANGEDW: TvnSelected(nmtv); break; case NativeMethods.TVN_BEGINDRAGA: case NativeMethods.TVN_BEGINDRAGW: TvnBeginDrag(MouseButtons.Left, nmtv); break; case NativeMethods.TVN_BEGINRDRAGA: case NativeMethods.TVN_BEGINRDRAGW: TvnBeginDrag(MouseButtons.Right, nmtv); break; case NativeMethods.TVN_BEGINLABELEDITA: case NativeMethods.TVN_BEGINLABELEDITW: m.Result = TvnBeginLabelEdit((NativeMethods.NMTVDISPINFO)m.GetLParam(typeof(NativeMethods.NMTVDISPINFO))); break; case NativeMethods.TVN_ENDLABELEDITA: case NativeMethods.TVN_ENDLABELEDITW: m.Result = TvnEndLabelEdit((NativeMethods.NMTVDISPINFO)m.GetLParam(typeof(NativeMethods.NMTVDISPINFO))); break; case NativeMethods.NM_CLICK: case NativeMethods.NM_RCLICK: MouseButtons button = MouseButtons.Left; NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); Point pos = Cursor.Position; pos = PointToClientInternal(pos); tvhip.pt_x = pos.X; tvhip.pt_y = pos.Y; IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); if (nmtv->nmhdr.code != NativeMethods.NM_CLICK || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0) { button = nmtv->nmhdr.code == NativeMethods.NM_CLICK ? MouseButtons.Left : MouseButtons.Right; } // The treeview's WndProc doesn't get the WM_LBUTTONUP messages when // LBUTTONUP happens on TVHT_ONITEM. This is a comctl quirk. // We work around that by calling OnMouseUp here. if (nmtv->nmhdr.code != NativeMethods.NM_CLICK || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0 || FullRowSelect) { if (hnode != IntPtr.Zero && !ValidationCancelled) { OnNodeMouseClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), button, 1, pos.X, pos.Y)); OnClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0)); OnMouseClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0)); } } if (nmtv->nmhdr.code == NativeMethods.NM_RCLICK) { TreeNode treeNode = NodeFromHandle(hnode); if (treeNode != null && (treeNode.ContextMenu != null || treeNode.ContextMenuStrip != null)) { ShowContextMenu(treeNode); } else { treeViewState[TREEVIEWSTATE_showTreeViewContextMenu] = true; SendMessage(NativeMethods.WM_CONTEXTMENU, Handle, SafeNativeMethods.GetMessagePos()); } m.Result = (IntPtr)1; } if (!treeViewState[TREEVIEWSTATE_mouseUpFired]) { if (nmtv->nmhdr.code != NativeMethods.NM_CLICK || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0) { // The treeview's WndProc doesn't get the WM_LBUTTONUP messages when // LBUTTONUP happens on TVHT_ONITEM. This is a comctl quirk. // We work around that by calling OnMouseUp here. OnMouseUp(new MouseEventArgs(button, 1, pos.X, pos.Y, 0)); treeViewState[TREEVIEWSTATE_mouseUpFired] = true; } } break; } } }
protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_WINDOWPOSCHANGING: case NativeMethods.WM_NCCALCSIZE: case NativeMethods.WM_WINDOWPOSCHANGED: case NativeMethods.WM_SIZE: // While we are changing size of treeView to avoid the scrollbar; dont respond to the window-sizing messages. if (treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs]) { //Debug.WriteLineIf(treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs], "Sending message directly to DefWndProc() : " + m.ToString()); DefWndProc(ref m); } else { base.WndProc(ref m); } break; case NativeMethods.WM_HSCROLL: base.WndProc(ref m); if (DrawMode == TreeViewDrawMode.OwnerDrawAll) { //VsW : 432718 Invalidate(); } break; case NativeMethods.WM_PRINT: WmPrint(ref m); break; case NativeMethods.TVM_SETITEMA: case NativeMethods.TVM_SETITEMW: base.WndProc(ref m); if (this.CheckBoxes) { NativeMethods.TV_ITEM item = (NativeMethods.TV_ITEM) m.GetLParam(typeof(NativeMethods.TV_ITEM)); // Check for invalid node handle if (item.hItem != IntPtr.Zero) { NativeMethods.TV_ITEM item1 = new NativeMethods.TV_ITEM(); item1.mask = NativeMethods.TVIF_HANDLE | NativeMethods.TVIF_STATE; item1.hItem = item.hItem; item1.stateMask = NativeMethods.TVIS_STATEIMAGEMASK; UnsafeNativeMethods.SendMessage(new HandleRef(null, this.Handle), NativeMethods.TVM_GETITEM, 0, ref item1); TreeNode node = NodeFromHandle(item.hItem); node.CheckedStateInternal = ((item1.state >> 12) > 1); } } break; case NativeMethods.WM_NOTIFY: NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR) m.GetLParam(typeof(NativeMethods.NMHDR)); switch (nmhdr.code) { case NativeMethods.TTN_GETDISPINFOA: case NativeMethods.TTN_GETDISPINFOW: // MSDN: // Setting the max width has the added benefit of enabling multiline // tool tips! // UnsafeNativeMethods.SendMessage(new HandleRef(nmhdr, nmhdr.hwndFrom), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width); WmNeedText(ref m); m.Result = (IntPtr)1; return; case NativeMethods.TTN_SHOW: if (WmShowToolTip(ref m)) { m.Result = (IntPtr)1; return; } else { base.WndProc(ref m); break; } default: base.WndProc(ref m); break; } break; case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY: WmNotify(ref m); break; case NativeMethods.WM_LBUTTONDBLCLK: WmMouseDown(ref m, MouseButtons.Left, 2); //just maintain state and fire double click.. in final mouseUp... treeViewState[TREEVIEWSTATE_doubleclickFired] = true; //fire Up in the Wndproc !! treeViewState[TREEVIEWSTATE_mouseUpFired] = false; //problem getting the UP... outside the control... // CaptureInternal = true; break; case NativeMethods.WM_LBUTTONDOWN: try { treeViewState[TREEVIEWSTATE_ignoreSelects] = true; FocusInternal(); } finally { treeViewState[ TREEVIEWSTATE_ignoreSelects] = false; } //Always Reset the MouseupFired.... treeViewState[TREEVIEWSTATE_mouseUpFired] = false; NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); tvhip.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam); tvhip.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam); hNodeMouseDown = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); // This gets around the TreeView behavior of temporarily moving the selection // highlight to a node when the user clicks on its checkbox. if ((tvhip.flags & NativeMethods.TVHT_ONITEMSTATEICON) != 0) { //We donot pass the Message to the Control .. so fire MouseDowm ... OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); if (!ValidationCancelled && CheckBoxes) { TreeNode node = NodeFromHandle(hNodeMouseDown); bool eventReturn = TreeViewBeforeCheck(node, TreeViewAction.ByMouse); if (!eventReturn && node != null) { node.CheckedInternal = !node.CheckedInternal; TreeViewAfterCheck(node, TreeViewAction.ByMouse); } } m.Result = IntPtr.Zero; } else { WmMouseDown(ref m, MouseButtons.Left, 1); } downButton = MouseButtons.Left; break; case NativeMethods.WM_LBUTTONUP: case NativeMethods.WM_RBUTTONUP: NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO(); tvhi.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam); tvhi.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam); IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi); //Important for CheckBoxes ... click needs to be fired ... // if(hnode != IntPtr.Zero) { if (!ValidationCancelled && !treeViewState[TREEVIEWSTATE_doubleclickFired] & !treeViewState[TREEVIEWSTATE_mouseUpFired]) { //OnClick(EventArgs.Empty); //If the hit-tested node here is the same as the node we hit-tested //on mouse down then we will fire our OnNodeMoseClick event. if (hnode == hNodeMouseDown) { OnNodeMouseClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam))); } OnClick(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); OnMouseClick(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); } if (treeViewState[TREEVIEWSTATE_doubleclickFired]) { treeViewState[TREEVIEWSTATE_doubleclickFired] = false; if (!ValidationCancelled) { //OnDoubleClick(EventArgs.Empty); OnNodeMouseDoubleClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam))); OnDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); OnMouseDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); } } } if (!treeViewState[TREEVIEWSTATE_mouseUpFired]) OnMouseUp(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); treeViewState[TREEVIEWSTATE_doubleclickFired] = false; treeViewState[TREEVIEWSTATE_mouseUpFired] = false; CaptureInternal = false; //always clear our hit-tested node we cached on mouse down hNodeMouseDown = IntPtr.Zero; break; case NativeMethods.WM_MBUTTONDBLCLK: //fire Up in the Wndproc !! treeViewState[TREEVIEWSTATE_mouseUpFired] = false; WmMouseDown(ref m, MouseButtons.Middle, 2); break; case NativeMethods.WM_MBUTTONDOWN: //Always Reset the MouseupFired.... treeViewState[TREEVIEWSTATE_mouseUpFired] = false; WmMouseDown(ref m, MouseButtons.Middle, 1); downButton = MouseButtons.Middle; break; case NativeMethods.WM_MOUSELEAVE: // if the mouse leaves and then reenters the TreeView // NodeHovered events should be raised. prevHoveredNode = null; base.WndProc(ref m); break; case NativeMethods.WM_RBUTTONDBLCLK: WmMouseDown(ref m, MouseButtons.Right, 2); //just maintain state and fire double click.. in final mouseUp... treeViewState[TREEVIEWSTATE_doubleclickFired] = true; //fire Up in the Wndproc !! treeViewState[TREEVIEWSTATE_mouseUpFired] = false; //problem getting the UP... outside the control... // CaptureInternal = true; break; case NativeMethods.WM_RBUTTONDOWN: //Always Reset the MouseupFired.... treeViewState[TREEVIEWSTATE_mouseUpFired] = false; //Cache the hit-tested node for verification when mouse up is fired NativeMethods.TV_HITTESTINFO tvhit = new NativeMethods.TV_HITTESTINFO(); tvhit.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam); tvhit.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam); hNodeMouseDown = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhit); WmMouseDown(ref m, MouseButtons.Right, 1); downButton = MouseButtons.Right; break; //# VS7 15052 case NativeMethods.WM_SYSCOLORCHANGE: SendMessage(NativeMethods.TVM_SETINDENT, Indent, 0); base.WndProc(ref m); break; case NativeMethods.WM_SETFOCUS: // If we get focus through the LBUttonDown .. we might have done the validation... // so skip it.. if (treeViewState[TREEVIEWSTATE_lastControlValidated]) { treeViewState[TREEVIEWSTATE_lastControlValidated] = false; WmImeSetFocus(); DefWndProc(ref m); OnGotFocus(EventArgs.Empty); } else { base.WndProc(ref m); } break; case NativeMethods.WM_CONTEXTMENU: if (treeViewState[TREEVIEWSTATE_showTreeViewContextMenu]) { treeViewState[TREEVIEWSTATE_showTreeViewContextMenu] = false; base.WndProc(ref m); } else { // this is the Shift + F10 Case.... TreeNode treeNode = SelectedNode; if (treeNode != null && (treeNode.ContextMenu != null || treeNode.ContextMenuStrip !=null)) { Point client; client = new Point(treeNode.Bounds.X , treeNode.Bounds.Y + treeNode.Bounds.Height / 2); // VisualStudio7 # 156, only show the context menu when clicked in the client area if (ClientRectangle.Contains( client )) { if (treeNode.ContextMenu != null) { treeNode.ContextMenu.Show(this, client); } else if (treeNode.ContextMenuStrip !=null) { bool keyboardActivated = (unchecked((int)(long)m.LParam) == -1); treeNode.ContextMenuStrip.ShowInternal(this, client, keyboardActivated); } } } else { // in this case we dont have a selected node. The base // will ensure we're constrained to the client area. base.WndProc (ref m); } } break; default: base.WndProc(ref m); break; } }
/// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.WmNeedText"]/*' /> /// <devdoc> /// </devdoc> /// <internalonly/> private void WmNeedText(ref Message m) { NativeMethods.TOOLTIPTEXT ttt = (NativeMethods.TOOLTIPTEXT) m.GetLParam(typeof(NativeMethods.TOOLTIPTEXT)); string tipText = controlToolTipText; NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); Point pos = Cursor.Position; pos = PointToClientInternal(pos); tvhip.pt_x = pos.X; tvhip.pt_y = pos.Y; IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) { TreeNode tn = NodeFromHandle(hnode); if (ShowNodeToolTips && tn != null && (!string.IsNullOrEmpty(tn.ToolTipText))) { tipText = tn.ToolTipText; } else if (tn != null && tn.Bounds.Right > this.Bounds.Right) { tipText = tn.Text; } else { tipText = null; } } ttt.lpszText = tipText; ttt.hinst = IntPtr.Zero; // RightToLeft reading order // if (RightToLeft == RightToLeft.Yes) { ttt.uFlags |= NativeMethods.TTF_RTLREADING; } Marshal.StructureToPtr(ttt, m.LParam, false); }
private unsafe bool WmShowToolTip(ref Message m) { NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam; IntPtr tooltipHandle = nmhdr->hwndFrom; NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); Point pos = Cursor.Position; pos = PointToClientInternal(pos); tvhip.pt_x = pos.X; tvhip.pt_y = pos.Y; IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) { TreeNode tn = NodeFromHandle(hnode); if (tn != null) { if (!ShowNodeToolTips) // default ToolTips { Rectangle bounds = tn.Bounds; bounds.Location = this.PointToScreen(bounds.Location); UnsafeNativeMethods.SendMessage(new HandleRef(this, tooltipHandle), NativeMethods.TTM_ADJUSTRECT, 1, ref bounds); SafeNativeMethods.SetWindowPos(new HandleRef(this, tooltipHandle), NativeMethods.HWND_TOPMOST, bounds.Left, bounds.Top, 0, 0, NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOZORDER); return true; } } } return false; }
/// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.OnMouseHover"]/*' /> /// <devdoc> /// In order for the MouseHover event to fire for each item in a TreeView, /// the node the mouse is hovering over is found. Each time a new node is hovered /// over a new event is raised. /// </devdoc> protected override void OnMouseHover(EventArgs e) { /// Hover events need to be caught for each node /// within the TreeView so the appropriate /// NodeHovered event can be raised. NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); Point pos = Cursor.Position; pos = PointToClientInternal(pos); tvhip.pt_x = pos.X; tvhip.pt_y = pos.Y; IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) { TreeNode tn = NodeFromHandle(hnode); if (tn != prevHoveredNode && tn != null) { OnNodeMouseHover( new TreeNodeMouseHoverEventArgs(tn)); prevHoveredNode = tn; } } if (!hoveredAlready) { base.OnMouseHover(e); hoveredAlready = true; } ResetMouseEventArgs(); }
/// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.GetNodeAt1"]/*' /> /// <devdoc> /// Returns the TreeNode at the given location in tree view coordinates. /// </devdoc> public TreeNode GetNodeAt(int x, int y) { NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO(); tvhi.pt_x = x; tvhi.pt_y = y; IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi); return(hnode == IntPtr.Zero ? null : NodeFromHandle(hnode)); }
/// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.HitTest"]/*' /> /// <devdoc> /// Gives the information about which part of the treeNode is at the given x, y. /// </devdoc> public TreeViewHitTestInfo HitTest(int x, int y) { NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO(); tvhi.pt_x = x; tvhi.pt_y = y; IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi); TreeNode node = (hnode == IntPtr.Zero ? null : NodeFromHandle(hnode)); TreeViewHitTestLocations loc = (TreeViewHitTestLocations)tvhi.flags; return (new TreeViewHitTestInfo(node, loc)); }