【问题标题】:Restrict Control / UIElement within screen boundaries限制屏幕边界内的 Control / UIElement
【发布时间】:2014-09-22 07:28:08
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    一旦你得到边界矩形 - 你可以使用它的尺寸而不是 ActualWidth/ActualHeight 和被操纵对象的 X&Y 来确定它可以或不能去的地方。

    【讨论】:

    • 是的,当控件与屏幕边界对齐时有效。但是当控件旋转一个角度时,将ActualWidth 添加到x 其中x 是左上角并不会给出右上角。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多