【问题标题】:Find node clicked under context menu查找在上下文菜单下单击的节点
【发布时间】:2010-09-05 09:01:36
【问题描述】:

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

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

【问题讨论】:

    标签: c# winforms treeview contextmenu


    【解决方案1】:

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

    【讨论】:

    • 非常感谢,我对解决方案有一点补充:您还可以使用“_NodeMouseClick”事件,它会为您提供“TreeNodeMouseClickEventArgs e”,在这种情况下,您可以只使用 e.Node 和不必费心检查节点是否为空。
    • 我通过 MouseDown 事件而不是 MouseUp 获得了想要的结果。
    【解决方案2】:

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

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

    【讨论】:

    • 鼠标事件参数没有.Node
    • 是的,但是 TreeNodeMouseClickEventArgs(传递给 NodeMouseClick 事件)可以。所以我的解决方案是有效的,不会像其他一些解决方案那样过于复杂
    【解决方案3】:

    我发现标准的 Windows 树视图行为选择行为非常烦人。例如,如果您使用资源管理器并右键单击一个节点并单击属性,它会突出显示该节点并显示您单击的节点的属性对话框。但是当您从对话框返回时,突出显示的节点是在您右键单击之前之前选择/突出显示的节点。我发现这会导致可用性问题,因为我一直对我是否在正确的节点上采取行动感到困惑。

    因此,在我们的许多 GUI 中,我们通过右键单击更改选定的树节点,以免混淆。这可能与像 Explorer 这样的标准 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 );
               }
            }
         }
      }
    

    【讨论】:

    • 这对我来说是最好的解决方案,因为它实际上选择了您单击的节点。
    【解决方案4】:

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

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

    【讨论】:

    • 我也更喜欢这个。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      与 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 属性将反映正确的节点。

      【讨论】:

        【解决方案7】:

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

        首先选择项目而不是仅将其用于上下文菜单有一些优势。第一个是用户有一个关于他点击了哪个项目以及菜单与哪个项目相关联的视觉指示。第二个是这样可以更容易地与其他调用上下文菜单的方法(例如键盘快捷键)保持兼容。

        【讨论】:

          【解决方案8】:

          这是我的做法。

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

          【讨论】:

            【解决方案9】:

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

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

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

            【讨论】:

              【解决方案10】:

              我想提出使用点击事件的替代方案,使用上下文菜单的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 事件来代替。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多