Reputation: 3461
The problem with the ListView.GetItemAt
method is shown in the screenshot below.
this.listView1 = new System.Windows.Forms.ListView();
this.SuspendLayout();
//
// listView1
//
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView1.Location = new System.Drawing.Point(0, 0);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(717, 511);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(717, 511);
this.Controls.Add(this.listView1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listView1.OwnerDraw = true;
listView1.View = View.LargeIcon;
listView1.DrawItem += ListView1_DrawItem;
listView1.MouseMove += ListView1_MouseMove;
for (int i = 1; i <= 10; ++i)
{
listView1.Items.Add($"item {i}", 0);
}
}
private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
ListViewItem item = listView1.GetItemAt(e.X, e.Y);
if (LastHoveredItem != null)
{
ListViewItem item2 = LastHoveredItem;
LastHoveredItem = null;
listView1.Invalidate(item2.Bounds);
}
if (item != null)
{
LastHoveredItem = item;
listView1.Invalidate(item.Bounds);
}
else
{
LastHoveredItem = null;
}
}
private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if (LastHoveredItem == e.Item)
{
e.Graphics.FillRectangle(Brushes.Yellow, e.Item.Bounds);
}
else
{
e.Graphics.FillRectangle(Brushes.Green, e.Item.Bounds);
}
}
internal ListViewItem LastHoveredItem = null;
The rectangle under the mouse cursor should be yellow, but it is green like the others that are not hovered.
Upvotes: 0
Views: 1404
Reputation: 527
Sharing an alternative solution that find the ListViewSubItem under the mouse cursor, credits to Fredrik Mörk (appsloveworld.com):
private void listViewCreateEntity_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control == true && e.KeyCode == Keys.C)
{
var mousePos = listViewCreateEntity.PointToClient(Cursor.Position);
ListViewItem lvItem = listViewCreateEntity.GetItemAt(mousePos.X, mousePos.Y);
if (null != lvItem)
{
var lvSubItem = lvItem.GetSubItemAt(mousePos.X, mousePos.Y);
Clipboard.SetText(lvSubItem.Text);
Debug.WriteLine("Hit! Clipboard copy: " + lvSubItem.Text);
}
}
}
Upvotes: 0
Reputation: 125277
ListView.GetItemAt
gets the item if the label or icon rectangle of the icon contains the point. It's not what you are looking for. You need to check the entire item.
You can use either of the following methods:
Example - Detect hot item in DrawItem
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
//...
var p = listView1.PointToClient(Cursor.Position);
if (e.Item.GetBounds(ItemBoundsPortion.Entire).Contains(p))
{
//e.Item is Hot
}
else
{
//e.Item is Normal
}
//...
}
Upvotes: 1