Assume a context menu is associated with a listview. Upon opening the
context menu, is there a way to determine which row in the listview
that the context menu was invoked upon?
Yes...
There are two ways in which you can achieve this.
First you'll have to handle the MouseDown event of the ListView
control.
Suppose you have these three options in the context menu
Copy
Paste
Delete
The event handlers for these will not be called when the user right
clicks on the ListView and the context menu appears but the MouseDown
event will fire on a right click.
Now you can use the method GetChildAt(int x, int y)
or
HitTest(int x, int y)
to find out the exact listViewItem.
HitTest is a better method to use as it will give you the subitem if
any, when the sub item was clicked.
The only drawback of these is that if the user right clicks on a
ListViewItem but not on the text which is displayed there then it
doesn't works.
I wrote a small program and its working fine.
I'll copy paste the code here.
Add a ListView and a ContextMenuStrip to your form.
Add Copy, Paste, Cut, Delete as the four menu items.
Set the FullRowSelected of the ListView to true. (Necessary)
Set the GridLines to true.
Set the View to Details.
Here's the code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace ContextMenuListViewItem
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializeUserComponent();
}
private void InitializeUserComponent()
{
ListViewItem listViewItem1 = new
System.Windows.Forms.ListViewItem(new string[] {
"file1.txt",
"Documents",
"29 Kb",
"Text File"}, -1);
ListViewItem listViewItem2 = new
System.Windows.Forms.ListViewItem(new string[] {
"mypic.jpeg",
"My Pictures",
"387 Kb",
"JPEG File"}, -1);
ListViewItem listViewItem3 = new
System.Windows.Forms.ListViewItem(new string[] {
"Terminator III.avi",
"My Movies",
"700 Mb",
"AVI File"}, -1);
ListViewItem listViewItem4 = new
System.Windows.Forms.ListViewItem(new string[] {
"Help.chm",
"My eBooks",
"12 Mb",
"CHM File"}, -1);
ColumnHeader columnHeader1 = new
System.Windows.Forms.ColumnHeader();
columnHeader1.Text = "File Name";
columnHeader1.Width = 111;
ColumnHeader columnHeader2 = new
System.Windows.Forms.ColumnHeader();
columnHeader2.Text = "Folder";
columnHeader2.Width = 126;
ColumnHeader columnHeader3 = new
System.Windows.Forms.ColumnHeader();
columnHeader3.Text = "Size";
ColumnHeader columnHeader4 = new
System.Windows.Forms.ColumnHeader();
columnHeader4.Text = "Type";
columnHeader4.Width = 108;
this.listView1.Columns.AddRange(new
System.Windows.Forms.ColumnHeader[] {
columnHeader1,
columnHeader2,
columnHeader3,
columnHeader4});
this.listView1.ContextMenuStrip = this.contextMenuStrip1;
this.listView1.Items.AddRange(new
System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2,
listViewItem3,
listViewItem4});
}
private ListViewItem lvItem = null;
private void contextMenuStrip1_Opening(object sender,
CancelEventArgs e)
{
// If its a right click
if(!MousePosition.IsEmpty)
{
Point p = PointToClient(new Point(MousePosition.X,
MousePosition.Y));
// Using HitTest
/*//
ListViewHitTestInfo lvhtInfo =
this.listView1.HitTest(p);
if (lvhtInfo != null)
{
lvItem = lvhtInfo.Item;
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}\r\n", p.ToString());
sb.AppendFormat("{0}\r\n", lvhtInfo.ToString());
if (lvhtInfo.Item != null)
{
sb.AppendFormat("{0}\r\n",
lvhtInfo.Item.ToString());
}
if (lvhtInfo.SubItem != null)
{
sb.AppendFormat("{0}\r\n",
lvhtInfo.SubItem.ToString());
}
textBox1.Text = sb.ToString();
}
//*/
// Using GetItemAt
//*//
ListViewItem currLvItem =
this.listView1.GetItemAt(p.X, p.Y);
if (currLvItem != null)
{
lvItem = currLvItem;
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}\r\n", p.ToString());
sb.AppendFormat("{0}\r\n", currLvItem.ToString());
sb.AppendFormat("{0}\r\n", currLvItem.Text);
if (currLvItem.SubItems != null)
{
foreach (ListViewItem.ListViewSubItem
lvSubItem in currLvItem.SubItems)
{
sb.AppendFormat("{0}\r\n",
lvSubItem.Text);
}
}
textBox1.Text = sb.ToString();
}
//*/
}
contextMenuStrip1.Items.Clear();
ToolStripMenuItem tsmItem = null;
if (lvItem != null)
{
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Copy " + lvItem.Text;
contextMenuStrip1.Items.Add(tsmItem);
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Paste";
contextMenuStrip1.Items.Add(tsmItem);
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Cut " + lvItem.Text;
contextMenuStrip1.Items.Add(tsmItem);
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Delete " + lvItem.Text;
contextMenuStrip1.Items.Add(tsmItem);
}
else
{
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Copy";
contextMenuStrip1.Items.Add(tsmItem);
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Paste";
contextMenuStrip1.Items.Add(tsmItem);
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Cut";
contextMenuStrip1.Items.Add(tsmItem);
tsmItem = new ToolStripMenuItem();
tsmItem.Text = "Delete";
contextMenuStrip1.Items.Add(tsmItem);
}
}
}
}
You'll notice that when you use GetItemAt(), the ListViewSubItem are
not taken into account.
Hope this helps
Prateek Raman