Search code examples
wpfmvvmrectanglesuielement

How can I find UIElements in a rectangle in WPF?


I need to find UIElements in (rectangle/area/bounds).

MainWindow I'm doing the following:

  • I register the mouse down as the start position.
  • I regsiter the mouse up position.
  • Now I need to find ll (buttons, textboxes, etc) in the rectangle between start postion and the end position.

I found in the msdn the HitTest approach but it is only for one point. I think, walking through all points in the founded rectangle it is a performance disaster.

http://msdn.microsoft.com/en-us/library/ms752097.aspx

My code based on MVVM pattern:

private ObservableCollection<UIElementViewModel> wells;   
private Point stratPoint; // Mouse down
public ICommand MouseUpRightCommand
{
  get
  {
    if (this.mouseUpRightCommand == null)
    {
      this.mouseUpRightCommand = new RelayCommands(
        param =>
       {
          if (param is MouseButtonEventArgs)
          {
            var e = (param as MouseButtonEventArgs);

            //Set the end point
            endPosition = e.GetPosition(((ItemsControl)e.Source));

            // for example, here I want to find all controls(UIElements) in the
            // founded rectangle of stratPoint and endPosition.

          }
        });
    }

    return this.mouseUpRightCommand;
  }
}

Any other idea or a better approach?

Thanks


Solution

  • I would use FrameworkElement (which extends UIElement) instead of UIElement, in order to use ActualWidth and ActualHeight properties

    Then create a static class which does some math MouseUtils

    with those static fields

        private static double _dContainerTop;
        private static double _dContainerBottom;
        private static double _dContainerLeft;
        private static double _dContainerRight;
        private static double _dCursorTop;
        private static double _dCursorLeft;
        private static double _dCursorRight;
        private static double _dCursorBottom;
    

    and those static methods

        private static void FindValues(FrameworkElement element, Visual rootVisual)
        {
            var containerTopLeft = container.TransformToAncestor(rootVisual).Transform(new Point(0, 0));
    
            _dContainerTop = containerTopLeft.Y;
            _dContainerBottom = _dContainerTop + container.ActualHeight;
            _dContainerLeft = containerTopLeft.X;
            _dContainerRight = _dContainerLeft + container.ActualWidth;
    
        }
    

    and

        public static bool IsElementUnderRectCursor(FrameworkElement element, Point startPoint, Point endPoint, Visual rootVisual)
        {
           _dCursorTop=Math.Min(startPoint.Y, endPoint.Y);
           _dCursorBottom=Math.Max(startPoint.Y, endPoint.Y);
           _dCursorLeft=Math.Min(startPoint.X, endPoint.X);
           _dCursorRight=Math.Max(startPoint.X, endPoint.X);
    
            FindValues(container, rootVisual);
            if (_dContainerTop < _dCursorTop|| _dCursorBottom< _dContainerBottom )
            {
                return false;
            }
            if (_dContainerLeft < _dCursorLeft|| _dContainerRight < _dCursorRight)
            {
                return false;
            }
            return true;
        }
    

    Rootvisual being your window for example;

    Then loop over ObservableCollection<FrameworkElement> wells and call that function IsElementUnderRectCursor.

    This is inspired from: Kinecting the Dots