Shirohida

Context menu for column headers of .NET ListView

ListView doesn’t provide ColumnHeaderMouseClick event so I had to find a workaround to display context menu for column headers. There is a way to do this by resorting to Windows API but my solution is easier.

Let’s say we’ve got a ListView control called contentsListView and two menus: generalContextMenu and headerContextMenu. generalContextMenu should be displayed when user right-clicks on an item and headerContextMenu should be displayed when he clicks on a column header.

Set the list view’s property ContextMenuStrip to generalContextMenu:

contentListView.ContextMenuStrip = generalContextMenu;

Add handler for Opening event of generalContextMenu:

generalContextMenuStrip.Opening += generalContextMenu_Opening;

I have played with debugger a bit and found out that contentListView.GetItemAt returns first visible item of the list even when we actually click on a column header. So, when we get some value this means we either clicked on an item or on a column header. Any list item is located below the header, so if the item Position.Y is less than MousePosition.Y then user clicked on a column header.

Here is the code for the handler:

private void generalContextMenu_Opening(object sender, CancelEventArgs e)
{
	Point pt = contentListView.PointToClient(new Point(MousePosition.X, MousePosition.Y));
	ListViewItem item = contentListView.GetItemAt(pt.X, pt.Y);

	// Not an item or a column header
	if (item == null)
	{
		e.Cancel = true;
		return;
	}

	// Is it a column header?
	if (item.Position.Y > pt.Y)
	{
		e.Cancel = true;
		headerContextMenu.Show(MousePosition);
	}
}