【发布时间】:2010-09-05 09:01:36
【问题描述】:
如何在树列表中找出上下文菜单被激活的节点?例如,右键单击一个节点并从菜单中选择一个选项。
我无法使用 TreeViews 的 SelectedNode 属性,因为该节点只是被右键单击而未被选中。
【问题讨论】:
标签: c# winforms treeview contextmenu
如何在树列表中找出上下文菜单被激活的节点?例如,右键单击一个节点并从菜单中选择一个选项。
我无法使用 TreeViews 的 SelectedNode 属性,因为该节点只是被右键单击而未被选中。
【问题讨论】:
标签: c# winforms treeview contextmenu
您可以将鼠标单击事件添加到 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 树视图行为选择行为非常烦人。例如,如果您使用资源管理器并右键单击一个节点并单击属性,它会突出显示该节点并显示您单击的节点的属性对话框。但是当您从对话框返回时,突出显示的节点是在您右键单击之前之前选择/突出显示的节点。我发现这会导致可用性问题,因为我一直对我是否在正确的节点上采取行动感到困惑。
因此,在我们的许多 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 );
}
}
}
}
【讨论】:
重新提出这个问题,因为我发现这是一个更好的解决方案。
我改用NodeMouseClick 事件。
void treeview_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if( e.Button == MouseButtons.Right )
{
tree.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);
}
【讨论】:
与 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 属性将反映正确的节点。
【讨论】:
如果您希望上下文菜单依赖于所选项目,我认为最好的办法是使用 Jonesinator 的代码来选择单击的项目。然后,您的上下文菜单内容可以依赖于所选项目。
首先选择项目而不是仅将其用于上下文菜单有一些优势。第一个是用户有一个关于他点击了哪个项目以及菜单与哪个项目相关联的视觉指示。第二个是这样可以更容易地与其他调用上下文菜单的方法(例如键盘快捷键)保持兼容。
【讨论】:
这是我的做法。
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
e.Node.TreeView.SelectedNode = e.Node;
}
【讨论】:
您可以使用的另一个选项是拥有一个具有选定节点的全局变量。您只需要使用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 事件来代替。
【讨论】: