I'm working on a project manager type of application with a pretty straightforward design: projects and their constituent steps are read from the database and displayed hierarchically as nodes in a
TreeView control. Clicking on a project or step node retrieves the details and generates a tab in an adjoining
TabControl. This was being handled by intercepting the tree's
NodeMouseClick event and was working great.
The problem was that expanding or collapsing a project node also triggered
NodeMouseClick. I needed to figure out how to perform my action when the node was actually clicked, and not when the expand / collapse bullet next to the node was clicked.
The blindingly obvious solution
I spent a while searching the web and trying the offered solutions. All were along the lines of "intercept an earlier event, test to see what happened, then set a global variable that will be read in a later event." None of these solutions could be adapted to what I needed. So I started poking around and found the solution in the event's own parameter.
TreeNodeMouseClickEventArgs. This class contains
Node, which gives the tree node that was clicked, and
Location, which gives the mouse's position relative to the tree's client space when the click occurred. Tree nodes have a property,
Bounds, which gives the node's rectangle coordinates relative to the tree view. A quick test verified that the expand / collapse bullet is outside the node's boundary. So I added
to my button test in the event and voila!
I could perform the action only when the node was really clicked, and not when its collapse state was changing. In VB, this looks like:
Private Sub CurrentTree_NodeMouseClick(ByVal sender As Object, _
ByVal e As TreeNodeMouseClickEventArgs) _
If e.Node.Bounds.Contains(e.Location) AndAlso e.Button = Windows.Forms.MouseButtons.Left Then
void CurrentTree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
if (e.Node.Bounds.Contains(e.Location) && e.Button == MouseButtons.Left)
Works like a charm, at least with .Net 3.5. I don't expect it would be different with any other flavors of the Framework.
Update 1: Made some minor grammar changes, clarified a few points, and added a C# example. I mostly use VB, so please let me know if the C# code is off.