2014-09-22 2 views
1

У меня есть Canvas в качестве базы моего приложения, и у него есть несколько элементов управления, которые пользователь может перемещать, вращать и масштабировать, используя их соответствующие ManipulationDelta.Ограничение контроля/UIElement в границах экрана

Проблема заключается в том, что пользователь может случайно нести управление из Canvas или границы экрана при перемещении элемента управления пальцем.

Как ограничить перемещение этих элементов управления в пределах Canvas?

ответ

2

Вы можете проверить управление ToolWindow и FlickBehavior в WinRT XAML Toolkit для вдохновения.

Это довольно простой общий. Если вы не сделаете инерции это может быть что-то вроде этого:

if (x < 0) 
    x = 0; 
if (x > _canvas.ActualWidth - this.AssociatedObject.ActualWidth) 
    x = _canvas.ActualWidth - this.AssociatedObject.ActualWidth; 
if (y < 0) 
    y = 0; 
if (y > _canvas.ActualHeight - this.AssociatedObject.ActualHeight) 
    y = _canvas.ActualHeight - this.AssociatedObject.ActualHeight; 

После того, как вы повернете или масштаб - вам нужно сделать некоторые матрицы преобразования операций, чтобы получить прямоугольник. К счастью, на платформе есть несколько способов сделать это легким для вас, а именно методы TransformToVisual() и TransformPoint(). У меня также есть вспомогательный класс с расширением, который делает его еще проще - проверьте VisualTreeHelperExtensions.GetBoundingRect().

/// <summary> 
/// Gets the bounding rectangle of a given element 
/// relative to a given other element or visual root 
/// if relativeTo is null or not specified. 
/// </summary> 
/// <remarks> 
/// Note that the bounding box is calculated based on the corners of the element relative to itself, 
/// so e.g. a bounding box of a rotated ellipse will be larger than necessary and in general 
/// bounding boxes of elements with transforms applied to them will often be calculated incorrectly. 
/// </remarks> 
/// <param name="dob">The starting element.</param> 
/// <param name="relativeTo">The relative to element.</param> 
/// <returns></returns> 
/// <exception cref="System.InvalidOperationException">Element not in visual tree.</exception> 
public static Rect GetBoundingRect(this FrameworkElement dob, FrameworkElement relativeTo = null) 
{ 
    if (DesignMode.DesignModeEnabled) 
    { 
     return Rect.Empty; 
    } 

    if (relativeTo == null) 
    { 
     relativeTo = Window.Current.Content as FrameworkElement; 
    } 

    if (relativeTo == null) 
    { 
     throw new InvalidOperationException("Element not in visual tree."); 
    } 

    if (dob == relativeTo) 
    { 
     return new Rect(0, 0, relativeTo.ActualWidth, relativeTo.ActualHeight); 
    } 

    var ancestors = dob.GetAncestors().ToArray(); 

    if (!ancestors.Contains(relativeTo)) 
    { 
     throw new InvalidOperationException("Element not in visual tree."); 
    } 

    var topLeft = 
     dob 
      .TransformToVisual(relativeTo) 
      .TransformPoint(new Point()); 
    var topRight = 
     dob 
      .TransformToVisual(relativeTo) 
      .TransformPoint(
       new Point(
        dob.ActualWidth, 
        0)); 
    var bottomLeft = 
     dob 
      .TransformToVisual(relativeTo) 
      .TransformPoint(
       new Point(
        0, 
        dob.ActualHeight)); 
    var bottomRight = 
     dob 
      .TransformToVisual(relativeTo) 
      .TransformPoint(
       new Point(
        dob.ActualWidth, 
        dob.ActualHeight)); 

    var minX = new[] { topLeft.X, topRight.X, bottomLeft.X, bottomRight.X }.Min(); 
    var maxX = new[] { topLeft.X, topRight.X, bottomLeft.X, bottomRight.X }.Max(); 
    var minY = new[] { topLeft.Y, topRight.Y, bottomLeft.Y, bottomRight.Y }.Min(); 
    var maxY = new[] { topLeft.Y, topRight.Y, bottomLeft.Y, bottomRight.Y }.Max(); 

    return new Rect(minX, minY, maxX - minX, maxY - minY); 
} 

После того, как вы получите ограничивающий прямоугольник - вы можете использовать его размеры вместо ActualWidth/ActualHeight и X & Y из манипулируют объект, чтобы определить, где он может или не может идти.

+0

Да, это работает, когда элементы управления выровнены с границами экрана. Но когда элементы управления повернуты на угол, добавление 'ActualWidth' в' x', где x - верхняя левая точка, не дает верхней правой части. –

+0

Я обновил свой ответ для этого сценария. –

+0

Это отлично работает! –