4

I would like to implement multiple selection of shapes using a drag rectangle. I've many shapes on a canvas like that : enter image description here

Thoses shapes are bound to corresponding models (MVVM). My selection rectangle looks like that : enter image description here

When I finished drawing the selection rectangle (mouse up event), I run this code :

var itemToSelect = ViewModel.ItemsInCanvas.Where((item) =>
{
    // TODO : test each types of shapes to know if the selection rectangle intersects with it
}).ToList();

I have differents kinds of object model for the shapes:

  • The quadrilateral : I can get (in code) the coordinates of each of the four points.
  • The triangle : I can get (in code) the coordinates of each of the three points.
  • The curve : I can get the path data (as string).
  • The ligne : I can get the two points (the sinusoidal is the same object)
  • The circle : I can get the height and the width.

I can also get the top and the left of each shape.

All thoses shapes are stored on a list in my main view model: ItemsInCanvas

When I enter the code above, I would like to test each element to know if they intersects with the selection rectangle (whose I know the coordinates).

My first try was (only for the curve item):

var itemToSelect = ViewModel.ItemsInCanvas.Where((item) =>
{
    if (item is CurveItem)
    {
        // I got my Curve Item
        CurveItem curveItem = (item as CurveItem);
        // I got the selection rectangle
        RectangleGeometry SelectionRectangleGeometry = new RectangleGeometry(SelectionRectangle);
        // Is the rectangle intersecting the shape ?
        if (SelectionRectangleGeometry.FillContainsWithDetail(Geometry.Parse(curveItem.Data)) == IntersectionDetail.Intersects)
            return true;
    }
}).ToList();

But it doesnt work, the test returns allway the same thing : Intersects.

I think the test doesn't take care of the position of each shapes (like if it was in absolute, not in relative).

Do you know how I can do my tests ?

Ana
  • 841
  • 10
  • 28
Ben
  • 3,972
  • 8
  • 43
  • 82

1 Answers1

4

You could perhaps solve this problem by doing a geometry hit test in the visual layer. Pass your Canvas and selection Geometry to a method like shown below, which returns a list of all Shapes that are hit by the geometry.

private IList<Shape> GetSelectedShapes(UIElement element, Geometry geometry)
{
    var shapes = new List<Shape>();

    VisualTreeHelper.HitTest(element, null,
        result =>
        {
            var shape = result.VisualHit as Shape;

            if (shape != null)
            {
                shapes.Add(shape);
            }

            return HitTestResultBehavior.Continue;
        },
        new GeometryHitTestParameters(geometry));

    return shapes;
}

You may start reading about Hit Testing in the Visual Layer.

Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Thank you it works but now, I have to find the model object bound to the shape. – Ben Jun 03 '13 at 10:01
  • You could put the model object into the [Tag](http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.tag.aspx) property of each Shape. – Clemens Jun 04 '13 at 09:46
  • How can I do this when I use a Rectangle for drawing the selectionbox? I can't figure out how to draw geometries on a canvas. – Janco de Vries Dec 09 '16 at 10:32