silviubogan
silviubogan

Reputation: 3461

How to get the correct ListViewItem under the mouse cursor?

The problem with the ListView.GetItemAt method is shown in the screenshot below.

Designer code

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);

Code-behind

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;

Screenshot

The rectangle under the mouse cursor should be yellow, but it is green like the others that are not hovered.

screenshot

Upvotes: 0

Views: 1404

Answers (3)

Mosca Pt
Mosca Pt

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

AJITH
AJITH

Reputation: 1175

Why can't you use the listView1.FocusedItem property

Upvotes: 0

Reza Aghaei
Reza Aghaei

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

Related Questions