2014-09-22 64 views
1

我有一个Canvas作为我的应用程序的基础,它有几个控件,用户可以使用它们各自的ManipulationDelta's来移动,旋转和缩放。在屏幕边界内限制控制/ UIElement

问题是,用户可能会意外地将控件移出Canvas或屏幕边界,同时用手指移动控件。

如何限制这些控件在Canvas内的移动?

回答

2

您可以在WinRT XAML Toolkit中检查ToolWindow控件和FlickBehavior以获取灵感。

这是非常基本的整体。如果你不这样做惯性,可能是这样的:

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()方法。我也有一个辅助类,使用en扩展方法,使它更容易 - 检查出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); 
} 

一旦你的边界RECT - 您可以使用它的尺寸,而不是被操纵的对象ActualWidth/ActualHeight和X & y以确定它可以或不可以去。

+0

是的,这是控件与屏幕边界对齐时的作品。但是,当控件旋转一个角度时,将'ActualWidth'添加到'x',其中x是左上角的点不会给出右上角的点。 – 2014-09-26 05:16:42

+0

我已经更新了我对这种情况的回答。 – 2014-09-26 15:05:42

+0

这很好! – 2014-09-30 02:44:19