Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drag User Control, but keep it inside the bounds of its parent in WPF

Tags:

c#

wpf

I have a user control that I am dragging inside of a grid. The Z-Index is set pretty high so that I can keep it above the other children. Dragging the control works perfectly, but if a user wants to move the control outside of the grid it will allow it.

enter image description here How do I keep it from leaving the bounds of the parent Grid control, here is what I have now:

   private System.Windows.Point _anchorPoint;
    private System.Windows.Point _currentPoint;
    private bool _isInDrag;

   private void UserControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var element = sender as FrameworkElement;
        _anchorPoint = e.GetPosition(null);
        if (element != null) element.CaptureMouse();
        _isInDrag = true;
        e.Handled = true;
    }

    private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (!_isInDrag) return;
        var element = sender as FrameworkElement;
        if (element != null) element.ReleaseMouseCapture();
        _isInDrag = false;
        e.Handled = true;
    }

   private void UserControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_isInDrag) return;
            _currentPoint = e.GetPosition(null);

            UIElement container = VisualTreeHelper.GetParent(_parentGrid) as UIElement;
            System.Windows.Point relativeLocation = _parentGrid.TranslatePoint(new System.Windows.Point(0, 0), container);

            if (_currentPoint.X > relativeLocation.X) return;
            if(_currentPoint.Y >= relativeLocation.Y)return;

            _transform.X += _currentPoint.X - _anchorPoint.X;
            _transform.Y += (_currentPoint.Y - _anchorPoint.Y);
            RenderTransform = _transform;
            _anchorPoint = _currentPoint;
        }

The "relativeLocation" is always 0x0, so thats not working. Any ideas would greatly be appreciated.

*Note : I know if I changed my UserControl to a Window it would mitigate all of the issues that I am having. But to be honest, it looks great this way and I really don't want to clutter the window up. This system opens up as a dashboard that consumes the user's' entire window ( is opened on a separate window). So when you open a window here, its doesn't flow right.

like image 977
Kevin B Burns Avatar asked Oct 30 '22 00:10

Kevin B Burns


2 Answers

I don't think you need the relativeLocation. The math can be a bit annoying to get right, though. Try this approach, it worked well when I tested it:

    private void UserControl_MouseMove(object sender, MouseEventArgs e)
    {
        if (!_isInDrag) return;
        _currentPoint = e.GetPosition(null);

        //This is the change to the position that we want to apply
        Point delta = new Point();
        delta.X = _currentPoint.X - _anchorPoint.X;
        delta.Y = _currentPoint.Y - _anchorPoint.Y;

        //Calculate user control edges
        var leftEdge   = Margin.Left + _transform.X + delta.X;
        var topEdge    = Margin.Top + _transform.Y + delta.Y;
        var rightEdge  = Width + Margin.Left + _transform.X + delta.X;
        var bottomEdge = Height + Margin.Top + _transform.Y + delta.Y;

        //Set the delta to 0 if it goes over _parentGrid edges
        if (leftEdge < 0) delta.X = 0;
        if (topEdge  < 0) delta.Y = 0;

        if (rightEdge  > _parentGrid.Width)  delta.X = 0;
        if (bottomEdge > _parentGrid.Height) delta.Y = 0;

        //Apply the delta to the user control
        _transform.X += delta.X;
        _transform.Y += delta.Y;
        RenderTransform = _transform;
        _anchorPoint = _currentPoint;
    }
like image 129
Tee Avatar answered Nov 15 '22 06:11

Tee


This is a start:

Point position = _parentGrid.PointToScreen(new Point(0, 0));
PresentationSource source = PresentationSource.FromVisual(_parentGrid);
position = source.CompositionTarget.TransformFromDevice.Transform(position);

Now you have the screen coordinates of the parent grid. The call to Transform() is important as it will convert pixels to WPF device independent pixels, matching the system DPI setting.

like image 35
l33t Avatar answered Nov 15 '22 05:11

l33t