【问题标题】:Check if usercontrol is within Window Bounds检查用户控件是否在窗口边界内
【发布时间】:2013-04-04 09:26:58
【问题描述】:

我有一个项目需要能够在屏幕上拖动用户控件(托管在网格中)。这适用于以下代码:

void MyUserControl_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    var ct = (CompositeTransform) RenderTransform ?? new CompositeTransform {CenterX = 0.5, CenterY = 0.5};
        ct.TranslateX += e.Delta.Translation.X;
        ct.TranslateY += e.Delta.Translation.Y;
}

问题是用户控件可以一直拖出屏幕区域。为了防止这种情况,我尝试了这里显示的示例:http://msdn.microsoft.com/en-us/library/system.windows.uielement.manipulationdelta.aspx

不幸的是,它使用 containingRect.Contains(shapeBounds) 而在 Windows 8 中,我们需要用 Point 替换 shapeBounds(this is a rect)。我不确定如何使用它。

那么问题是我们如何确保用户控件或任何 UIElement 不能被拖出 windows 8 商店应用程序中的 Window.Current.Bounds 区域?

谢谢。

编辑:有关 xaml 结构的更多详细信息:

主页包含一个水平和垂直对齐设置为拉伸的网格。根据需要将用户控件添加到此网格中。每个用户控件都有一个包含 3 个不同视图(全屏、窗口和小)的父网格。根据用户的选择显示视图。只有在显示窗口网格时才必须应用拖动行为。所以我们有这个

<Grid> <!-- this is the parent grid on mainpage with horizontal and vertical alignment to stretch-->
   <Grid> <!-- this is the usercontrol's main grid (added to above grid via code). This grid must be draggable if the below grid is window -->
         <Grid /> <!-- this is one of the child grids that is shown based on user's choice (fullscreen, window or small view).-->
   </Grid>
</Grid>

在更改布局方面我没有太多选择。在用户控件中使用上面的 ManipulationDelta 事件(根据显示的子网格启用/禁用),我能够获得拖动行为,但控件可能会超出窗口范围。那么有什么方法可以通过代码而不是 xaml 在 WinRTXamlToolkit 中添加以下 FlickBehavior 或根据某些条件启用/禁用行为?

<i:Interaction.Behaviors>
   <views:HeavyFlickBehavior />
</i:Interaction.Behaviors>

【问题讨论】:

  • 你的用户控件在哪里?在画布上?
  • 它在网格内,但如果使用网格有问题,可以移动到画布上。
  • 我认为您必须使用TransformToVisualTransformPoint 手动检查用户控件的边缘是否接近边界
  • 您拥有源代码,因此您可以轻松添加或删除该行为。您可以简单地清除或设置控件上的 ManipulationMode 以启用/禁用该行为。顺便说一句 - 不要使用 HeavyFlickBehavior - 这是 WinRT XAML 工具包中用于测试内存泄漏的压力测试类。每个实例使用 100MB 的 RAM! :)
  • 谢谢菲利普!不知道我怎么没想到启用/禁用操作模式。如果您不介意,最后一件事 - 有没有办法通过代码而不是 xaml 附加行为?

标签: c# windows-8 windows-runtime windows-store-apps winrt-xaml


【解决方案1】:

您可以查看 WinRT XAML 工具包中的 FlickBehavior 以获取有关如何使用父级 CanvasCanvas.Top/Left 属性而不是 RenderTransform 来实现此目的的示例,假设 Canvas 定义了您的界限。

这是一个摘要:

private void OnAssociatedObjectManipulationStarting(object sender, ManipulationStartingRoutedEventArgs e)
{
    _startPosition = new Point(
        Canvas.GetLeft(this.AssociatedObject),
        Canvas.GetTop(this.AssociatedObject));
}

private void OnAssociatedObjectManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs manipulationDeltaRoutedEventArgs)
{
    var dx = manipulationDeltaRoutedEventArgs.Cumulative.Translation.X;
    var dy = manipulationDeltaRoutedEventArgs.Cumulative.Translation.Y;

    var x = _startPosition.X + dx;
    var y = _startPosition.Y + dy;

    if (manipulationDeltaRoutedEventArgs.IsInertial)
    {
        while (x < 0 ||
               x > _canvas.ActualWidth - this.AssociatedObject.ActualWidth)
        {
            if (x < 0)
                x = -x;
            if (x > _canvas.ActualWidth - this.AssociatedObject.ActualWidth)
                x = 2 *
                    (_canvas.ActualWidth - this.AssociatedObject.ActualWidth) -
                    x;
        }

        while (y < 0 ||
               y > _canvas.ActualHeight - this.AssociatedObject.ActualHeight)
        {
            if (y < 0)
                y = -y;
            if (y > _canvas.ActualHeight - this.AssociatedObject.ActualHeight)
                y = 2 * (_canvas.ActualHeight - this.AssociatedObject.ActualHeight) -
                    y;
        }
    }
    else
    {
        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;
    }

    Canvas.SetLeft(this.AssociatedObject, x);
    Canvas.SetTop(this.AssociatedObject, y);
}

【讨论】:

  • 嗨 Filip,感谢您的详细回复。我将在今天晚些时候对其进行测试并恢复。是否可以使用 RenderTransform 和 Grid 作为容器来实现相同的功能?
  • 是的,假设您的转换仅更新 X/Y 属性,您只需更新其 X/Y 而不是 Canvas.Left/Top。唯一的问题可能是您拖动的项目大于容器,因为这可能会导致剪辑。我认为我的代码甚至没有考虑到它,所以它仍然可能崩溃或挂起。只需确保将子控件的 Horizo​​ntalAlignment 设置为 Left,VerticalAlignment 设置为 Top,Margin 设置为 0。
  • 嗨 Filip,尝试了上述解决方案,如果父级是带有子 uielement 的画布,它工作正常。但我有一个稍微困难的问题。我已经编辑了我的问题以便更好地解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2015-04-03
  • 2016-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多