1

I'am trying to implement a click and drag selection like the one in windows explorer (the blue selection rectangle that occurs when you keep the mouse button down and you move the mouse).

So basically I have a ListView, with styled and templated ListViewItem. I have added MouseEnter and MouseLeave event on my ListViewItem (with the EventSetter), It works fine except when the left mouse button is down. In this case, the events doesn't get fired, which is not good for what I'm trying to achieve.

Do you know if there is any good workaround for this, I want to know when I'm over an item or not when the left mouse button is down.

For now I've tried with the VisualTreeHelper.HitTest(), but I only know when I cross a ListViewItem, and I need to know when I leave it.

Thank you.

StrAbZ
  • 579
  • 1
  • 8
  • 24

3 Answers3

1

You have to capture the mouse UIElement.CaptureMouse when the button is pressed and then release the mouse UIElement.ReleaseMouseCapture during the MouseUp event. You do not have to worry about any other events because all mouse input goes to your UIElement during the capture.

This form of selection is called "lasso select" and most widgets in Windows apps support it. In fact, the ListView itself already does.

Tergiver
  • 14,171
  • 3
  • 41
  • 68
  • Ok, but I still don't understand something, since I capture the mouse (and release it), on my list view, how can I get the information about which Item a move over ? I don't have item event, and I don't know any way of checking if the mouse is in the bounds of a ListViewItem (except what I'm already doing with the VisualTreeHelper.HitTest()) – StrAbZ Jan 29 '11 at 14:32
  • @StrAbZ: Googled it for you: http://manfredlange.blogspot.com/2009/04/listviewgetitemat-in-wpf-application.html – Tergiver Jan 29 '11 at 15:16
  • Thank you, this seems to do part of the job. It works for the mouse pointer, I still need to find out how to detect which items are under my selection zone, and not just the mouse pointer. – StrAbZ Jan 29 '11 at 16:28
  • Walk through `ListView.Items` and use their visual to test against your rectangle. – Tergiver Jan 29 '11 at 17:16
  • Here's an article expalining how to hit test against a Geometry object (which could be a rectangle): http://msdn.microsoft.com/en-us/library/ms748343.aspx – Tergiver Jan 29 '11 at 17:24
0

Even if your MouseEnter and Leave events were fired that would not provide a good method for selection because both events are irrelevant in the end: It does not matter if your mouse ever touched that folder or file, all that matters is if it is in the rectangle at the point in time when you release the button. This means that Mouse Up & Down should be enough. Depending on your list you might even be able to infer which items should be selected just from looking at the two Items on which those events occurred (e.g. if it's just a one-dimensional list as opposed to a two-dimensional grid).

If you have a grid you'd need more complex mechanics like keeping track of which area is covered and checking which items are inside or on the edge.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • The problem with this method is that my items only get selected when the user releases the mouse button, in my case I wanna be closer to the Windows explorer behavior, which means selecting/deselecting items when the mouse/"blue selection rectangle" is over an item. If I do the selection after it will do the jobs, but the look and feel and UX experience would not be as good as expected, and I wanna keep as much as possible a consistency with the windows default behavior. – StrAbZ Jan 28 '11 at 17:24
  • Then you could handle `MouseMove` on the `ListView`, test if the respective mouse button is down and also check if `Mouse.DirectlyOver` returns a `ListViewItem`. If it does you can either select it and/or deselect the item that the mouse was over last. Kinda complicated but it's just a small bit of logical interaction. – H.B. Jan 28 '11 at 17:31
  • I can have the mouse IsDirectlyOver, tested over each item, but this will require to have the MouseCapture removed, which I don't want. Unless I'm missing something. – StrAbZ Jan 29 '11 at 14:36
0

So I have found a different solution to handle this behavior.

I've started, with this stackoverflow answer Click and drag selection box in WPF

In the mouseMove, after modifying the selectionBox size, I select the items that are in the selectionBox region.

I do it this way :

 //Select all visible items in select region.
 Rect selectRect = new Rect(Canvas.GetLeft(selectionBox), Canvas.GetTop(selectionBox),
                (Canvas.GetLeft(selectionBox) + selectionBox.Width), (Canvas.GetTop(selectionBox) + selectionBox.Height));

 RectangleGeometry rr = new RectangleGeometry(selectRect);
 foreach (CustomElement elt in mainList.Items)
 {
  ListViewItem item = mainList.ItemContainerGenerator.ContainerFromItem(elt) as ListViewItem;
  Rect r = LayoutInformation.GetLayoutSlot(item);
  if (r.IntersectsWith(selectRect))
        item.IsSelected = true;
  else
        item.IsSelected = false;
 }

I've found that LayoutInformation can gives you the Rect that represent your object, so I can check if it intersect with the selectionBox Rect.

Community
  • 1
  • 1
StrAbZ
  • 579
  • 1
  • 8
  • 24