C# 在关联菜单下查找已单击的节点

C# 在关联菜单下查找已单击的节点,c#,winforms,treeview,contextmenu,C#,Winforms,Treeview,Contextmenu,如何找出树列表中上下文菜单已激活的节点?例如,右键单击节点并从菜单中选择一个选项 我无法使用TreeView“SelectedNode属性,因为该节点仅被右键单击而未被选中。您可以将鼠标单击事件添加到TreeView,然后使用GetNodeAt根据MouseEventArgs提供的鼠标坐标选择正确的节点 void treeView1MouseUp(object sender, MouseEventArgs e) { if(e.Button == MouseButtons.Right)

如何找出树列表中上下文菜单已激活的节点?例如,右键单击节点并从菜单中选择一个选项


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

您可以将鼠标单击事件添加到TreeView,然后使用GetNodeAt根据MouseEventArgs提供的鼠标坐标选择正确的节点

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);
        }
    }
}

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


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

我发现标准的windows treeview行为选择行为非常烦人。例如,如果正在使用资源管理器,右键单击某个节点并单击“属性”,则会高亮显示该节点并显示所单击节点的“属性”对话框。但是,当您从对话框返回时,高亮显示的节点是您右键单击之前选择/高亮显示的节点。我发现这会导致可用性问题,因为我总是对我是否在正确的节点上操作感到困惑

因此,在我们的许多GUI中,我们在右键单击时更改所选的树节点,这样就不会出现混淆。这可能与标准iwndos应用程序(如Explorer)不同(出于实用性原因,我倾向于在标准窗口应用程序之后对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 );
           }
        }
     }
  }

这是我的解决办法。将此行放入TreeView的NodeMouseClick事件:

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

与马库斯的回答类似,这是我发现对我有效的解决方案:

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的打开事件中,TreeView.SelectedNode属性将反映正确的节点。

恢复此问题,因为我发现这是一个更好的解决方案。 我使用
节点emouseclick
事件

void treeview_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if( e.Button == MouseButtons.Right )
    {
        tree.SelectedNode = e.Node;
    }
}
我是这样做的

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

这是一个非常古老的问题,但我仍然觉得它很有用。我使用的是上面一些答案的组合,因为我不希望右键单击的节点成为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);
}

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

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

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

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

private void Handle\u ContextMenu\u打开(对象发送方,事件参数e)
{
treeviewittestinfo=treeview.HitTest(treeview.PointToClient(Cursor.Position));
树节点上下文节点;
//是否存在打开上下文菜单的节点?
if(info!=null&&info.Node!=null)
{
contextNode=info.Node;
}
//设置上下文菜单元素的启用状态
menuEdit.Enabled=contextNode!=null;
menuDelete.Enabled=contextNode!=null;
}
我可以看出,这有以下优点:

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

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

鼠标事件args没有.NodeYeah,但treeNodeUseClickEventargs(传递到NodeMouseClick事件中)有。因此,我的解决方案是有效的,不像其他解决方案那样过于复杂。这是对我来说最好的解决方案,因为它实际上选择了您单击的节点。非常感谢,我在解决方案中添加了一个小内容:您也可以使用“\u NodeMouseClick”事件,该事件为您提供了一个“TreeNodeMouseClickEventArgs”在这种情况下,您可以只使用e.Node,而不必检查节点是否为null。我使用MouseDown事件而不是MouseUp获得了所需的结果。我也更喜欢这个。