Как я могу узнать, какой узел в древовидном списке было активировано контекстное меню? Например, щелкнув узел правой кнопкой мыши и выбрав параметр в меню.
Я не могу использовать свойство SelectedNode
TreeViews, потому что узел щелкается правой кнопкой мыши и не выбран.
Вы можете добавить событие щелчка мыши в 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);
}
}
}
Я получил желаемый результат с событием MouseDown вместо MouseUp.
Если вы хотите, чтобы контекстное меню зависело от выбранного элемента, лучше всего использовать код Jonesinator для выбора элемента, по которому щелкнули мышью. В этом случае содержимое контекстного меню может зависеть от выбранного элемента.
Выбор элемента первым, а не просто его использование для контекстного меню дает несколько преимуществ. Во-первых, у пользователя есть визуальная индикация того, на что он щелкнул и, следовательно, с каким элементом связано меню. Во-вторых, таким образом намного проще поддерживать совместимость с другими методами вызова контекстного меню (например, сочетаниями клавиш).
Я считаю, что стандартное поведение выбора поведения в виде дерева в Windows довольно раздражает. Например, если вы используете проводник и щелкаете правой кнопкой мыши узел и нажимаете «Свойства», он выделяет узел и отображает диалоговое окно свойств для узла, на котором вы щелкнули. Но когда вы вернетесь из диалогового окна, выделенный узел был ранее выбранным / выделенным до того, как вы щелкнули правой кнопкой мыши. Я считаю, что это вызывает проблемы с удобством использования, потому что я всегда не понимаю, действовал ли я на правильном узле.
Поэтому во многих наших графических интерфейсах мы изменяем выбранный узел дерева щелчком правой кнопки мыши, чтобы не возникало путаницы. Это может быть не то же самое, что и стандартное приложение iwndos, такое как Explorer (и я склонен строго моделировать наше поведение графического интерфейса после стандартных оконных приложений по причинам удобства использования), я считаю, что этот единственный случай исключения приводит к гораздо более пригодным для использования деревьям.
Вот код, который изменяет выбор при щелчке правой кнопкой мыши:
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;
Аргументы события мыши не имеют .Node
Да, но TreeNodeMouseClickEventArgs (которые передаются в событие NodeMouseClick) делают. Итак, мое решение работает и не является чрезмерно сложным, как некоторые другие решения.
Подобно ответу Маркуса, это решение, которое я нашел, сработало для меня:
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);
}
Другой вариант, с которым вы можете работать, - это иметь глобальную переменную с выбранным узлом. Вам просто нужно использовать TreeNodeMouseClickEventArgs
.
public void treeNode_Click(object sender, TreeNodeMouseClickEventArgs e)
{
_globalVariable = e.Node;
}
Теперь у вас есть доступ к этому узлу и его свойствам.
Я хотел бы предложить альтернативу использованию событий щелчка, используя событие 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;
}
Я вижу в этом следующие преимущества:
Примечание: если вы беспокоитесь, что пользователь, возможно, уже переместил мышь к моменту открытия меню, вместо этого можно использовать событие Opening
.
Большое спасибо, у меня есть небольшое дополнение к решению: вы также можете использовать событие «_NodeMouseClick», которое дает вам «TreeNodeMouseClickEventArgs e», и в этом случае вы можете просто использовать e.Node и не беспокоиться о проверке является ли узел нулевым или нет.