查找上下文菜单下单击的节点


74

如何找到上下文菜单已被激活的树形列表中的哪个节点?例如,右键单击节点,然后从菜单中选择一个选项。

我无法使用TreeViews的SelectedNode属性,因为仅右键单击该节点,未选中该节点。

Answers:


93

您可以将鼠标单击事件添加到TreeView中,然后在给定MouseEventArgs提供的鼠标坐标的情况下,使用GetNodeAt选择正确的节点。

void treeView1MouseUp(object sender, MouseEventArgs e)
{
    if(e.Button == MouseButtons.Right)
    {
        // Select the clicked node
        treeView1.SelectedNode = treeView1.GetNodeAt(e.X, e.Y);

        if(treeView1.SelectedNode != null)
        {
            myContextMenuStrip.Show(treeView1, e.Location);
        }
    }
}

7
非常感谢,我对解决方案有一点补充:您还可以使用“ _NodeMouseClick”事件,该事件为您提供“ TreeNodeMouseClickEventArgs e”,在这种情况下,您可以只使用e.Node,而不必费心检查节点是否为空。
SDM

我通过MouseDown事件而不是MouseUp获得了预期的结果。
哈维尔

21

这是我的解决方案。将此行放入TreeView的NodeMouseClick事件中:

 ((TreeView)sender).SelectedNode = e.Node;

鼠标事件args没有.Node
CAD

2
是的,但是TreeNodeMouseClickEventArgs(传递给NodeMouseClick事件)可以。因此,我的解决方案正在工作,并且没有像其他解决方案那样过于复杂
deej 2012年

12

我发现标准Windows Treeview行为选择行为非常烦人。例如,如果您正在使用资源管理器,然后右键单击某个节点并单击“属性”,它将突出显示该节点并显示您单击的节点的属性对话框。但是,当您从对话框中返回时,突出显示的节点是右键单击之前先前选择/突出显示的节点。我发现这会导致可用性问题,因为我永远困惑于我是否在正确的节点上采取了行动。

因此,在许多GUI中,我们都可以通过右键单击更改选定的树节点,以免造成混淆。这可能与资源管理器之类的标准iwndos应用程序不同(出于方便的原因,我倾向于在标准窗口应用程序之后强烈地对GUI行为进行建模),我相信这一例外情况会导致更多可用的树。

这是一些在右键单击期间更改选择的代码:

  private void tree_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
  {
     // only need to change selected note during right-click - otherwise tree does
     // fine by itself
     if ( e.Button == MouseButtons.Right )
     {         
        Point pt = new Point( e.X, e.Y );
        tree.PointToClient( pt );

        TreeNode Node = tree.GetNodeAt( pt );
        if ( Node != null )
        {
           if ( Node.Bounds.Contains( pt ) )
           {
              tree.SelectedNode = Node;
              ResetContextMenu();
              contextMenuTree.Show( tree, pt );
           }
        }
     }
  }

这对我来说是最好的解决方案,因为它实际上会选择您单击的节点。
CAD bloke 2012年

8

重提这个问题,因为我发现这是一个更好的解决方案。我改用NodeMouseClick事件。

void treeview_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if( e.Button == MouseButtons.Right )
    {
        tree.SelectedNode = e.Node;
    }
}

我也更喜欢这个。
乔伊·诺瓦克

3

这是一个非常老的问题,但我仍然发现它很有用。我将上面的一些答案组合在一起,因为我不希望右键单击的节点成为selectedNode。如果我选择了根节点并想删除它的一个子节点,那么我在删除子节点时不希望它被选中(我也在selectedNode上做一些我不想在右边发生的工作,点击)。这是我的贡献:

// Global Private Variable to hold right-clicked Node
private TreeNode _currentNode = new TreeNode();

// Set Global Variable to the Node that was right-clicked
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
        _currentNode = e.Node;
}

// Do something when the Menu Item is clicked using the _currentNode
private void toolStripMenuItem_Clicked(object sender, EventArgs e)
{
    if (_currentNode != null)
        MessageBox.Show(_currentNode.Text);
}

2

与Marcus的答案类似,这是我发现为我工作的解决方案:

private void treeView_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        treeView.SelectedNode = treeView.GetNodeAt(e.Location);
    }
}

如果将上下文菜单设置为每个单独的节点,则无需自己显示上下文菜单:

TreeNode node = new TreeNode();
node.ContextMenuStrip = contextMenu;

然后在ContextMenu的Opening事件中,TreeView.SelectedNode属性将反映正确的节点。


0

如果您希望上下文菜单依赖于所选项目,那么我认为最好是使用Jonesinator的代码选择单击的项目。然后,您的上下文菜单内容可以取决于所选项目。

首先选择项目,而不是仅将其用于上下文菜单,将带来一些优势。第一个是用户对他单击了哪个按钮以及菜单与哪个项目相关联具有视觉指示。第二个是,通过这种方式与其他调用上下文菜单的方法(例如键盘快捷键)保持兼容要容易得多。


0

这是我的方法。

private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
        e.Node.TreeView.SelectedNode = e.Node;
}

0

可以使用的另一个选项是使全局变量具有选定的节点。您只需要使用即可TreeNodeMouseClickEventArgs

public void treeNode_Click(object sender, TreeNodeMouseClickEventArgs e)
{
    _globalVariable = e.Node;
}

现在,您可以访问该节点及其属性。


0

我想提出一种使用单击事件的替代方法,即使用上下文菜单的Opened事件:

private void Handle_ContextMenu_Opened(object sender, EventArgs e)
{
    TreeViewHitTestInfo info = treeview.HitTest(treeview.PointToClient(Cursor.Position));
    TreeNode contextNode;

    // was there a node where the context menu was opened?
    if (info != null && info.Node != null)
    {
        contextNode = info.Node;
    }

    // Set the enabled states of the context menu elements
    menuEdit.Enabled = contextNode != null;
    menuDelete.Enabled = contextNode != null;
}

我可以看到以下优点:

  • 它不会更改所选节点
  • 不需要单独的事件处理程序来存储目标节点实例
  • 如果用户右键单击TreeView中的空白区域,则可以禁用菜单项

注意:如果您担心在打开菜单时用户可能已经移动了鼠标,则可以改用Opening事件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.