如何找到上下文菜单已被激活的树形列表中的哪个节点?例如,右键单击节点,然后从菜单中选择一个选项。
我无法使用TreeViews的SelectedNode
属性,因为仅右键单击该节点,未选中该节点。
Answers:
您可以将鼠标单击事件添加到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);
}
}
}
这是我的解决方案。将此行放入TreeView的NodeMouseClick事件中:
((TreeView)sender).SelectedNode = e.Node;
我发现标准Windows Treeview行为选择行为非常烦人。例如,如果您正在使用资源管理器,然后右键单击某个节点并单击“属性”,它将突出显示该节点并显示您单击的节点的属性对话框。但是,当您从对话框中返回时,突出显示的节点是右键单击之前先前选择/突出显示的节点。我发现这会导致可用性问题,因为我永远困惑于我是否在正确的节点上采取了行动。
因此,在许多GUI中,我们都可以通过右键单击更改选定的树节点,以免造成混淆。这可能与资源管理器之类的标准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 );
}
}
}
}
这是一个非常老的问题,但我仍然发现它很有用。我将上面的一些答案组合在一起,因为我不希望右键单击的节点成为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);
}
与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属性将反映正确的节点。
我想提出一种使用单击事件的替代方法,即使用上下文菜单的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
事件。