Question

I am working on a winform and on my UI there is a treeview, I found that the treenode will be highlighted even I did not click on the node by right mouse (eg, Node1 will be highlighted when I click on the following position), but i really do not like this behavior because I want to show a different context menu when I did not click on a treenode

+RootNode

  |_ Node1                [ Right Click Here, Node1 will be highlighted]
  |
  |_ Node2                [ Right Click Here, Node2 will be highlighted]
Was it helpful?

Solution 3

I have found another method to prevent the node to be highlight when the user not click on the node, and I only set the BackColor and ForeColor for each of the node when adding it to the tree

newNode.BackColor = treeview1.BackColor;
newNode.ForeColor = treeview1.ForeColor;
treeview1.Nodes.Add(newNode);

Then in the MouseDown event, set the SelectedNode property as following

 private void treeView1_MouseDown(object sender, MouseEventArgs e)
 {
        TreeNode Node = treeView1.GetNodeAt(e.Location);
        if (Node != null && Node.Bounds.Contains(e.Location))
            treeView1.SelectedNode = Node;
        else
            treeView1.SelectedNode = null;
 } 

OTHER TIPS

Going off of your comment to Kevin Wienhold's answer, you just want to allow the user to click in the empty space of the treeview and deselect any selected node.

You can do this by handling the MouseDown event of the TreeView control, and setting the SelectedNode property to null if the mouse was clicked over a location that does not contain a node. For example, you could use the following code:

private void myTreeView_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
    if (myTreeView.HitTest(e.Location).Node == null)
    {
        myTreeView.SelectedNode = null;
    }
}

This takes advantage of the HitTest method to determine which node is located at a particular point, specifying the location of the mouse event as the point to test. You don't need any other code to select nodes as usual when the user does click on them; that is handled automatically by the TreeView.


EDIT: As my comment to the question indicates, I'm still exceptionally unclear as to what you are trying to accomplish here. If you're actually interested in preventing a node from being temporarily highlighted while you hold down the right mouse button in the empty space to the side of the node, things get a little more complex.

I've looked into this problem before, and the tricky part is that window messages are not received while the mouse button is being held down, at least not until the mouse is moved (in which case, the node is no longer selected anyway). This behavior is apparently dictated by the operating system and not easily overridden using the standard .NET-provided events. You can try to cancel a click of the right button in the MouseDown event all day long, but the node is being selected by Windows before this event is ever raised in your control (remember that .NET-provided controls like the TreeView and ListView are simply wrappers around those same controls provided by the Windows API, which apparently implements this "select-node-while-right-button-held-down" behavior itself).

What does work, however, is overriding WndProc in a derived TreeView control, and handling the WM_RBUTTONDOWN message. But notice that even setting the SelectedNode property to null doesn't work here, because that's not processed until after Windows automatically selects the node as a response to the right mouse button being clicked—no matter what you do, you have to prevent the base TreeView control from receiving the WM_RBUTTONDOWN message. So, you have a couple of choices in how to handle this:

  1. You can simply cancel the right-click message by bailing out early with a return statement. Of course, this means you're not going to be able to handle this event in your MouseDown handler, because it's never actually passed to the control! So if you want to show a pop-up context menu, this probably won't work for you.

    public class NewTreeView : System.Windows.Forms.TreeView
    {
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_RBUTTONDOWN = 0x204;
            if (m.Msg == WM_RBUTTONDOWN)
            {
                return;
            }
            base.WndProc(ref m);
        }   
    }
    
  2. You can show your context menu in the overridden WndProc method as a response to the WM_RBUTTONDOWN message, and then return from the method without allowing the base class to handle the message. This does the exact same thing as the first solution (prevents the right-click event from causing the node to appear selected), but it does allow you to show a context menu (or do anything else that you want) whenever the right-click occurs. Of course, it does mean that all of the relevant code will have to be contained within your subclass of the TreeView control, not handled in your form's UI code, which may or may not be convenient for you.

    public class NewTreeView : System.Windows.Forms.TreeView
    {
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_RBUTTONDOWN = 0x204;
            if (m.Msg == WM_RBUTTONDOWN)
            {
                //Create and show a context menu
                var myContextMenu = new ContextMenuStrip();
                myContextMenu.Items.Add("First Item");
                myContextMenu.Items.Add("Second Item");
                return;
            }
            base.WndProc(ref m);
        }   
    }
    
  3. You could raise your own RightMouseClick event from your custom TreeView class as a response to the WM_RBUTTONDOWN message, which you could then handle as you wish from your form's UI code. By not passing the WM_RBUTTONDOWN message to the base TreeView control class, this accomplishes the same goal as the previous two suggestions, but allows you to handle the right-button click event in your form's UI code instead of having to put all of your logic into the subclassed control's WndProc.

    public class NewTreeView : System.Windows.Forms.TreeView
    {
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_RBUTTONDOWN = 0x204;
            if (m.Msg == WM_RBUTTONDOWN)
            {
                //Raise your custom event
                OnRightMouseClick(new EventArgs());
                return;
            }
            base.WndProc(ref m);
        }   
    }
    

try this

  void treeView1_MouseDown(object sender, MouseEventArgs e)
    {


        TreeViewHitTestInfo h = treeView1.HitTest(e.Location);

        if (h.Location != TreeViewHitTestLocations.Label && h.Location!= TreeViewHitTestLocations.None )
        {
            treeView1.SelectedNode = null;
        }
    }

If I understand you correctly you want no node to be selected if the user clicks into empty space within the TreeView. You could accomplish that by handling the MouseDown-Event of the Tree and setting the tree's SelectedNode property to TreeView.GetNodeAt(e.Location).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top