C# - 使用键盘时 TreeView 上下文菜单不合适
C# - TreeView Context Menu Out of Place when using keyboard
在简单的 C# WinForms 应用程序中,如果将上下文菜单分配给 Treeview 控件并且用户用鼠标右键单击节点,则上下文菜单会显示在光标所在节点的下方,但是如果使用键盘上下文菜单键或 shift+F10,则菜单会偏移并按长度显示在树视图的中间。为什么这是默认行为,上下文菜单如何显示在所选节点下?
查看reference source implementation, this seems to be a default implementation for any control (not just TreeView
) context menu handling when activated by keyboard, which works fine for TextBox
like controls. Interestingly, the documentation for WM_CONTEXTMENU message在备注部分包含以下语句
If the context menu is generated from the keyboard—for example, if the user types SHIFT+F10—then the x- and y-coordinates are -1 and the application should display the context menu at the location of the current selection rather than at (xPos, yPos).
显然没有遵循 WinForms TreeView
控件实现。
要获得所需的行为,您需要创建一个 TreeView
子类并自己处理 WM_CONTEXTMENU
消息,如下所示
class MyTreeView : TreeView
{
const int WM_CONTEXTMENU = 0x007B;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CONTEXTMENU && (long)m.LParam == -1 && this.ContextMenu != null)
{
var selectedNode = this.SelectedNode;
if (selectedNode == null) return;
var rect = selectedNode.Bounds;
var pt = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
if (!this.ClientRectangle.Contains(pt)) return;
this.ContextMenu.Show(this, pt);
return;
}
base.WndProc(ref m);
}
}
在简单的 C# WinForms 应用程序中,如果将上下文菜单分配给 Treeview 控件并且用户用鼠标右键单击节点,则上下文菜单会显示在光标所在节点的下方,但是如果使用键盘上下文菜单键或 shift+F10,则菜单会偏移并按长度显示在树视图的中间。为什么这是默认行为,上下文菜单如何显示在所选节点下?
查看reference source implementation, this seems to be a default implementation for any control (not just TreeView
) context menu handling when activated by keyboard, which works fine for TextBox
like controls. Interestingly, the documentation for WM_CONTEXTMENU message在备注部分包含以下语句
If the context menu is generated from the keyboard—for example, if the user types SHIFT+F10—then the x- and y-coordinates are -1 and the application should display the context menu at the location of the current selection rather than at (xPos, yPos).
显然没有遵循 WinForms TreeView
控件实现。
要获得所需的行为,您需要创建一个 TreeView
子类并自己处理 WM_CONTEXTMENU
消息,如下所示
class MyTreeView : TreeView
{
const int WM_CONTEXTMENU = 0x007B;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CONTEXTMENU && (long)m.LParam == -1 && this.ContextMenu != null)
{
var selectedNode = this.SelectedNode;
if (selectedNode == null) return;
var rect = selectedNode.Bounds;
var pt = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
if (!this.ClientRectangle.Contains(pt)) return;
this.ContextMenu.Show(this, pt);
return;
}
base.WndProc(ref m);
}
}