Equalsk
Equalsk

Reputation: 8214

Detect whether multiple ListView items were selected by dragging

I have a ListView with the View set to LargeIcon.
I specifically need to detect when multiple items were selected by dragging a selection box around them with the mouse. (For example I don't want to know when items were selected by CTRL + Click)

I thought I could simply do it by keeping track of whether the mouse was down while it was moving which would indicate dragging, then on mouse up if it was a drag then I can set another variable to indicate this.

In my example below mouseDown is set to true, but when I keep the mouse down and move it isDrag is never set to true and I can't see what I'm doing wrong.
(Edit: isDrag becomes true if I remove the if clause which is weird because as I said mouseDown is definitely true).

I realise the code is a little longer than it needs to be but it's for clarity.

bool mouseDown;
bool isDrag;
bool wasDrag;

private void listView1_MouseDown(object sender, MouseEventArgs args)
{
    wasDrag = false;
    mouseDown = true;
}

private void listView1_MouseMove(object sender, MouseEventArgs args)
{
    if (mouseDown)
        isDrag = true; // <-- Never becomes true, even though mouseDown is true
}

private void listView1_MouseUp(object sender, MouseEventArgs args)
{
    if (isDrag)
        wasDrag = true;

    mouseDown = false;
    isDrag = false;
}

I know it'll be something stupid. Please put me out of my misery.
Alternatively if someone knows of a better was to detect a dragging selection (what's the proper term?) then I'm all ears.

Upvotes: 0

Views: 155

Answers (2)

Equalsk
Equalsk

Reputation: 8214

After further investigation I've discovered that for a ListView control the MouseMove event will not fire while MouseDown is still occurring and fires immediately after releasing the mouse.
I can only assume that the logic built into this control that allows you to select multiple files by dragging a selection is messing with these events and essentially making them synchronous.

I've put together a basic workaround for this. It's not ideal but it does the job so I thought I'd share.

Basically when the mouse goes down I record the position. When the mouse goes up I check to see if it has moved more than a certain distance in any direction. If it has not I consider it a click, if it has I consider it a drag.

// Records the mouse position on mousedown
int beforeMoveX;
int beforeMoveY;

// How far in pixels the mouse must move in any direction
// before we consider this a drag rather than a click
int moveBounds = 20;

private void listView1_MouseDown(object sender, MouseEventArgs e)
{
    // Save the mouse position
    beforeMoveX = e.X;
    beforeMoveY= e.Y;
}

private void listView1_MouseUp(object sender, MouseEventArgs e)
{
    // Did we move more than the bounds in any direction?
    if (e.X < (beforeMoveX - moveBounds) || 
        e.X > (beforeMoveX + moveBounds) || 
        e.Y < (beforeMoveY - moveBounds) || 
        e.Y > (beforeMoveY + moveBounds))
    {
        // DRAGGED!
    }
    else
    {
        // NOT DRAGGED!
    }
}

Upvotes: 0

Batuta
Batuta

Reputation: 1714

Can you try this:

private void listView1_MouseMove(object sender, MouseEventArgs args)
{
    isDrag = mouseDown;
}

I think for some reason, your event listView1_MouseUp still fires, which makes your isDrag variable set to other than the intended value. Try to put breakpoints on both MouseMove and MouseUp events to see the sequence with which they are firing.

Upvotes: 1

Related Questions