我正在开发一个winform,在我的用户界面上有一个树视图,我发现即使我没有用鼠标右键单击该节点,树节点也会突出显示(例如,当我单击以下位置时,Node1 将突出显示),但我真的不喜欢这种行为,因为我想在没有单击树节点时显示不同的上下文菜单
+根节点
|_ Node1 [ Right Click Here, Node1 will be highlighted] | |_ Node2 [ Right Click Here, Node2 will be highlighted]
离开您对 Kevin Wienhold 的回答的评论,您只想允许用户单击树视图的空白区域并取消选择任何选定的节点。
您可以通过处理控件的MouseDown
事件并将该属性设置为是否在不包含节点的位置上单击鼠标来执行此操作。TreeView
SelectedNode
null
例如,您可以使用以下代码:
private void myTreeView_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (myTreeView.HitTest(e.Location).Node == null)
{
myTreeView.SelectedNode = null;
}
}
这利用该HitTest
方法来确定哪个节点位于特定点,将鼠标事件的位置指定为要测试的点。当用户确实单击它们时,您不需要任何其他代码来像往常一样选择节点;由TreeView
.
编辑:正如我对这个问题的评论所表明的那样,我仍然非常不清楚您要在这里完成什么。如果您真的有兴趣防止在节点侧面的空白处按住鼠标右键时暂时突出显示节点,那么事情会变得更复杂一些。
我以前研究过这个问题,棘手的部分是在按住鼠标按钮时不会收到窗口消息,至少在鼠标移动之前不会收到(在这种情况下,无论如何都不再选择节点) . 这种行为显然是由操作系统决定的,并且不容易使用标准的 .NET 提供的事件来覆盖。MouseDown
您可以尝试整天取消单击事件中的右键,但在您的控件中引发此事件之前,Windows 已选择该节点(请记住,.NET 提供的控件,如TreeView
和ListView
只是围绕那些由 Windows API 提供的相同控件,显然实现了这种“选择节点同时按住右键”行为本身)。
然而,真正起作用的是在派生控件中覆盖并处理消息。但请注意,即使将属性设置为在这里也不起作用,因为直到 Windows 自动选择节点作为对单击鼠标右键的响应之后才会处理它- 无论您做什么,您都必须阻止基本控件接收消息。所以,你有几个选择来处理这个问题:WndProc
TreeView
WM_RBUTTONDOWN
SelectedNode
null
TreeView
WM_RBUTTONDOWN
您可以通过声明提早退出来简单地取消右键单击消息return
。当然,这意味着您将无法在处理程序中处理此事件MouseDown
,因为它实际上从未传递给控件!因此,如果您想显示一个弹出式上下文菜单,这可能对您不起作用。
public class NewTreeView : System.Windows.Forms.TreeView
{
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_RBUTTONDOWN = 0x204;
if (m.Msg == WM_RBUTTONDOWN)
{
return;
}
base.WndProc(ref m);
}
}
您可以在重写的WndProc
方法中显示上下文菜单作为对消息的响应WM_RBUTTONDOWN
,然后return
从方法中显示,而不允许基类处理消息。这与第一个解决方案完全相同(防止右键单击事件导致节点显示为选中状态),但它确实允许您在右键单击时显示上下文菜单(或执行任何其他操作)发生。当然,这确实意味着所有相关代码都必须包含在TreeView
控件的子类中,而不是在表单的 UI 代码中处理,这对您来说可能方便也可能不方便。
public class NewTreeView : System.Windows.Forms.TreeView
{
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_RBUTTONDOWN = 0x204;
if (m.Msg == WM_RBUTTONDOWN)
{
//Create and show a context menu
var myContextMenu = new ContextMenuStrip();
myContextMenu.Items.Add("First Item");
myContextMenu.Items.Add("Second Item");
return;
}
base.WndProc(ref m);
}
}
您可以从自定义类中引发自己的 RightMouseClick
事件TreeView
作为对消息的响应WM_RBUTTONDOWN
,然后您可以从表单的 UI 代码中随意处理。通过不将WM_RBUTTONDOWN
消息传递给基本TreeView
控件类,这实现了与前两个建议相同的目标,但允许您在表单的 UI 代码中处理右键单击事件,而不必将所有逻辑放入子类中控制的WndProc
。
public class NewTreeView : System.Windows.Forms.TreeView
{
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_RBUTTONDOWN = 0x204;
if (m.Msg == WM_RBUTTONDOWN)
{
//Raise your custom event
OnRightMouseClick(new EventArgs());
return;
}
base.WndProc(ref m);
}
}
我找到了另一种方法来防止当用户不单击节点时节点被突出显示,并且我只在将每个节点添加到树时设置了 BackColor 和 ForeColor
newNode.BackColor = treeview1.BackColor;
newNode.ForeColor = treeview1.ForeColor;
treeview1.Nodes.Add(newNode);
然后在 MouseDown 事件中,设置 SelectedNode 属性如下
private void treeView1_MouseDown(object sender, MouseEventArgs e)
{
TreeNode Node = treeView1.GetNodeAt(e.Location);
if (Node != null && Node.Bounds.Contains(e.Location))
treeView1.SelectedNode = Node;
else
treeView1.SelectedNode = null;
}
试试这个
void treeView1_MouseDown(object sender, MouseEventArgs e)
{
TreeViewHitTestInfo h = treeView1.HitTest(e.Location);
if (h.Location != TreeViewHitTestLocations.Label && h.Location!= TreeViewHitTestLocations.None )
{
treeView1.SelectedNode = null;
}
}
如果我理解正确,如果用户单击 TreeView 中的空白区域,则不希望选择任何节点。您可以通过处理树的 MouseDown-Event 并将树的 SelectedNode 属性设置为 TreeView.GetNodeAt(e.Location) 来完成此操作。