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

76

如何确定树形列表中哪个节点已经激活了上下文菜单?例如,右键单击一个节点并从菜单中选择一个选项。

我不能使用TreeView的SelectedNode属性,因为该节点仅被右键单击而未被选中。

10个回答

97

您可以将鼠标单击事件添加到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);
        }
    }
}

8
非常感谢,我有一个小的解决方案补充: 您还可以使用“_NodeMouseClick”事件,它会给您提供一个“TreeNodeMouseClickEventArgs e”,在这种情况下,您只需使用e.Node,而不必担心检查节点是否为null。 - SDM
我使用MouseDown事件而不是MouseUp事件获得了所需的结果。 - Javier

22

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

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

鼠标事件参数没有 .Node 属性。 - CAD bloke
3
TreeNodeMouseClickEventArgs 是传递给 NodeMouseClick 事件的参数,所以我的解决方案可行且不像其他一些解决方案那样过于复杂。 - deej

12

我认为标准的Windows TreeView选择行为非常让人烦恼。例如,如果您正在使用资源管理器并右键单击一个节点,然后点击“属性”,它会突出显示该节点并显示所选节点的属性对话框。但是当您从对话框返回时,高亮显示的节点仍然是右键单击之前所选/高亮显示的节点。我发现这会导致可用性问题,因为我经常会混淆是否操作了正确的节点。

因此,在我们的许多GUI中,在右键单击时更改所选树节点,以消除混淆。这可能与像资源管理器这样的标准Windows应用程序不同(出于可用性原因,我倾向于严格模仿我们的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

11

重新提出这个问题,因为我认为这是一个更好的解决方案。 我使用NodeMouseClick事件。

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

我也更喜欢这个。 - Joey Novak

3

这是一个很老的问题,但我仍然觉得它很有用。我结合了上面一些答案的方法,因为我不想让右键单击的节点成为选定节点。如果我选择了根节点并且想要删除其中一个子节点,当我删除它时,我不希望该子节点被选中(我还在选定节点上做了一些工作,我不希望在右键单击时发生)。以下是我的贡献:

// 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

这是我如何做到的。

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

0

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

首先选择项目而不仅仅是在上下文菜单中使用它具有一些优点。第一个是用户可以视觉上知道他单击了哪个项目,因此菜单与哪个项目相关联。第二个是这样做更容易与其他调用上下文菜单的方法(例如键盘快捷键)兼容。


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”事件。


0

你可以使用另一种方式,创建一个全局变量来存储选中的节点。你只需要使用 TreeNodeMouseClickEventArgs 即可。

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接