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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-07-31 13:06:05  来源:igfitidea点击:

Find node clicked under context menu

提问by Sam

How can I find out which node in a tree list the context menu has been activated? For instance right-clicking a node and selecting an option from the menu.

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

I can't use the TreeViews' SelectedNodeproperty because the node is only been right-clicked and not selected.

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

采纳答案by Jonesinator

You can add a mouse click event to the TreeView, then select the correct node using GetNodeAt given the mouse coordinates provided by the MouseEventArgs.

您可以向 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);
        }
    }
}

回答by ICR

If you want the context menu to be dependent on the selected item you're best move I think is to use Jonesinator's code to select the clicked item. Your context menu content can then be dependent on the selected item.

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

Selecting the item first as opposed to just using it for the context menu gives a few advantages. The first is that the user has a visual indication as to which he clicked and thus which item the menu is associated with. The second is that this way it's a hell of a lot easier to keep compatible with other methods of invoking the context menu (e.g. keyboard shortcuts).

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

回答by Marcus Erickson

I find the standard windows treeview behavior selection behavior to be quite annoying. For example, if you are using Explorer and right click on a node and hit Properties, it highlights the node and shows the properties dialog for the node you clicked on. But when you return from the dialog, the highlighted node was the node previously selected/highlighted before you did the right-click. I find this causes usability problems because I am forever being confused on whether I acted on the right node.

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

So in many of our GUIs, we change the selected tree node on a right-click so that there is no confusion. This may not be the same as a standard iwndos app like Explorer (and I tend to strongly model our GUI behavior after standard window apps for usabiltiy reasons), I believe that this one exception case results in far more usable trees.

因此,在我们的许多 GUI 中,我们通过右键单击更改选定的树节点,以免混淆。这可能与像 Explorer 这样的标准 iwndos 应用程序不同(并且出于可用性的原因,我倾向于在标准窗口应用程序之后对我们的 GUI 行为进行强烈建模),我相信这个例外情况会导致更多可用的树。

Here is some code that changes the selection during the right click:

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

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

回答by deej

Here is my solution. Put this line into NodeMouseClick event of the TreeView:

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

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

回答by Trevor Elliott

Similar to Marcus' answer, this was the solution I found worked for me:

与 Marcus 的回答类似,这是我发现对我有用的解决方案:

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

You need not show the context menu yourself if you set it to each individual node like so:

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

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

Then inside the ContextMenu's Opening event, the TreeView.SelectedNode property will reflect the correct node.

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

回答by Beta Carotin

Reviving this question because I find this to be a much better solution. I use the NodeMouseClickevent instead.

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

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

回答by Ricky Manwell

Here is how I do it.

这是我如何做到的。

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

回答by George

This is a very old question, but I still found it useful. I am using a combination of some of the answers above, because I don't want the right-clicked node to become the selectedNode. If I have the root node selected and want to delete one of it's children, I don't want the child selected when I delete it (I am also doing some work on the selectedNode that I don't want to happen on a right-click). Here is my contribution:

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

回答by sparkyShorts

Another option you could run with is to have a global variable that has the selected node. You would just need to use the TreeNodeMouseClickEventArgs.

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

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

Now you have access to that node and it's properties.

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

回答by AeonOfTime

I would like to propose an alternative to using the click events, using the context menu's Openedevent:

我想提出一种使用单击事件的替代方法,使用上下文菜单的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;
}

This has the following advantages that I can see:

我可以看到这具有以下优点:

  • It does not change the selected node
  • No separate event handler needed to store the target node instance
  • Can disable menu items if the user right-clicks empty space in the TreeView
  • 它不会改变选定的节点
  • 无需单独的事件处理程序来存储目标节点实例
  • 如果用户右键单击 TreeView 中的空白区域,则可以禁用菜单项

Note: if you worry that the user may have already moved the mouse by the time the menu is opened, it is possible to use the Openingevent instead.

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