限制屏幕边界内的控制/ UIElement

时间:2014-09-22 07:28:09

标签: c# xaml canvas windows-store-apps microsoft-metro

我有一个Canvas作为我的应用的基础,它有几个控件,用户可以使用各自的ManipulationDelta移动,旋转和缩放。

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

如何在Canvas

中限制这些控件的移动

1 个答案:

答案 0 :(得分:2)

您可以查看ToolWindow控件和WinRT XAML工具包中的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);
}

获得边界矩形后,您可以使用其尺寸而不是ActualWidth / ActualHeight以及被操纵对象的X&amp; Y来确定它可以或不可以去的位置。