Найти узел, нажатый в контекстном меню

Как я могу узнать, какой узел в древовидном списке было активировано контекстным меню? Например, щелкнув узел правой кнопкой мыши и выбрав параметр в меню.

Я не могу использовать SelectedNode свойство TreeViews, потому что узел только щелкнул правой кнопкой мыши и не был выбран.

Ответов (10)

Решение

Вы можете добавить событие щелчка мыши в 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);
        }
    }
}

Подобно ответу Маркуса, это решение, которое я нашел, сработало для меня:

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 будет отражать правильный узел.

Возобновляя этот вопрос, я считаю, что это гораздо лучшее решение. NodeMouseClick Вместо этого я использую событие.

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

Я хотел бы предложить альтернативу использованию событий щелчка, используя 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 вместо этого можно использовать событие.

Другой вариант, с которым вы можете работать, - это иметь глобальную переменную, которая имеет выбранный узел. Вам просто нужно использовать расширение TreeNodeMouseClickEventArgs .

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

Теперь у вас есть доступ к этому узлу и его свойствам.

Если вы хотите, чтобы контекстное меню зависело от выбранного элемента, лучше всего использовать код Jonesinator для выбора элемента, по которому щелкнули мышью. Тогда содержимое вашего контекстного меню может зависеть от выбранного элемента.

Выбор элемента первым, а не просто его использование в контекстном меню дает несколько преимуществ. Во-первых, у пользователя есть визуальная индикация того, на что он щелкнул и, следовательно, с каким элементом связано меню. Во-вторых, таким образом намного проще поддерживать совместимость с другими методами вызова контекстного меню (например, сочетаниями клавиш).

Я считаю, что стандартное поведение выбора поведения в виде дерева в 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.

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

Вот мое решение. Поместите эту строку в событие NodeMouseClick TreeView:

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