In a simple C# WinForms application, if a context menu is assigned to a Treeview control and the user right-clicks a node with the mouse, the context menu shows up under the node at the point of the cursor, but if the keyboard context menu key or shift+F10 is used the menu is offset and displayed in the middle of the treeview by length. Why is this the default behavior and how can the context menu be shown under the selected node?
1 Answers
Looking at the 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 contains the following statement in the Remarks section
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).
which apparently is not followed by the WinForms TreeView
control implementation.
To get the desired behavior, you need to create a TreeView
subclass and process WM_CONTEXTMENU
message yourself, like this
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);
}
}