C# 将控件/UI元素限制在屏幕边界内

C# 将控件/UI元素限制在屏幕边界内,c#,xaml,canvas,windows-store-apps,microsoft-metro,C#,Xaml,Canvas,Windows Store Apps,Microsoft Metro,我有一个Canvas作为我的应用程序的基础,它有几个控件,用户可以使用各自的操作delta来移动、旋转和缩放 问题在于,当用户用手指移动控件时,可能会意外地将控件移出画布或屏幕边界 如何限制这些控件在画布中的移动?您可以检查控件和WinRT XAML工具包中的灵感 总的来说,这是相当基本的。如果不做惯性,可能是这样的: if (x < 0) x = 0; if (x > _canvas.ActualWidth - this.AssociatedObject.ActualWid

我有一个
Canvas
作为我的应用程序的基础,它有几个控件,用户可以使用各自的
操作delta
来移动、旋转和缩放

问题在于,当用户用手指移动控件时,可能会意外地将控件移出
画布
或屏幕边界

如何限制这些控件在
画布中的移动?

您可以检查控件和WinRT XAML工具包中的灵感

总的来说,这是相当基本的。如果不做惯性,可能是这样的:

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;

一旦获得边界矩形-您可以使用其尺寸,而不是操纵对象的实际宽度
/
实际高度
和X&Y来确定其可以或不能移动的位置。

是,当控件与屏幕边界对齐时,该操作有效。但是,当控件旋转一个角度时,将
实际宽度
添加到
x
中,其中x是左上角点,不会给出右上角点。
/// <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);
}