【问题标题】:Finding a UIElement's true position when within a PivotItem在 PivotItem 中查找 UIElement 的真实位置
【发布时间】:2014-08-18 17:05:19
【问题描述】:

我想获得嵌入在 PivotItem 中的 TextBlock 的屏幕位置和可见性 - 例如TB2 在屏幕上的位置和可见性:

    <phone:Pivot>
        <phone:PivotItem Header="first">
            <TextBlock x:Name="TB1" Text="Hello 1"></TextBlock>
        </phone:PivotItem>

        <phone:PivotItem Header="second" >
            <TextBlock x:Name="TB2" Text="Hello 2"></TextBlock>
        </phone:PivotItem>

        <phone:PivotItem Header="three" >
            <TextBlock x:Name="TB3" Text="Hello 3"></TextBlock>
        </phone:PivotItem>
    </phone:Pivot>

对于其他 Xaml 控件,我使用如下代码实现了这一点:

    public static Rect Position(this FrameworkElement element)
    {
        if (element.Visibility == Visibility.Collapsed)
            return Rect.Empty;

        if (element.Opacity < 0.01)
            return Rect.Empty;

        // Obtain transform information based off root element
        GeneralTransform gt = element.TransformToVisual(Application.Current.RootVisual);

        // Find the four corners of the element
        Point topLeft = gt.Transform(new Point(0, 0));
        Point topRight = gt.Transform(new Point(element.RenderSize.Width, 0));
        Point bottomLeft = gt.Transform(new Point(0, element.RenderSize.Height));
        Point bottomRight = gt.Transform(new Point(element.RenderSize.Width, element.RenderSize.Height));

        var left = Math.Min(Math.Min(Math.Min(topLeft.X, topRight.X), bottomLeft.X), bottomRight.X);
        var top = Math.Min(Math.Min(Math.Min(topLeft.Y, topRight.Y), bottomLeft.Y), bottomRight.Y);
        var position = new Rect(left, top, element.ActualWidth, element.ActualHeight);

        return position;
    }

但是,对于PivotItem 孩子,当PivotItem 不在屏幕上时,此计算不会提供预期的答案。相反,它提供了当PivotItem 在屏幕上滑回时项目将在屏幕上所处的位置的答案。在过渡期间,我可以看到使用上述方法正确计算了位置 - 例如在过渡期间,我会看到位置从屏幕的左/右正确滑入。

我查看了其他属性,例如 VisibleOpacity,看看这里是否使用了一些其他机制来隐藏屏幕外 PivotItem 或其 ParentGrandParent 之一等 -但所有这些似乎都会产生VisibleOpacity == 1.0 的结果。

我还尝试迭代 VisualTree 以查看是否有任何具有纯色背景的元素掩盖了“屏幕外”PivotItems - 但我在树中看不到任何元素。

这里还有其他要考虑的属性吗? PivotItem 内容在“屏幕外”时如何隐藏?如果我真的需要,我知道我可以使用PivotSelectedIndex 属性来帮助PivotItem 位置计算,但我希望尽可能避免SelectedIndex - 我'如果可能的话,我更喜欢使用通用的 Xaml 和 VisualTree 方法来获取位置。

【问题讨论】:

  • 我想解释(或至少是一个提示)将在 Pivot 的 ControlTemplate 中。但我似乎无法在我期望的地方找到它(“System.Windows.xaml”)。你碰巧知道如何找到它吗?
  • 在设计器中创建 PivotItem ControlTemplate 的副本会提供 1 in - gist.github.com/slodge/ba54683498ad2e2256f4 - 也添加到 Pivot 的 ControlTemplate 的副本中的 2 in 相同的要点 - gist.github.com/slodge/ba54683498ad2e2256f4#file-2
  • 那些模板非常稀疏。我猜他们在代码隐藏中做了所有的动画/状态变化?无论如何,我错了——那里没有太多线索,没有动画,甚至没有命名部分。
  • 您很可能会使用此工具找到答案(提供 21 天演示)xamlspy.com
  • 介意我问你想达到什么目的(为什么你需要这个信息用于屏幕外的数据透视项目)?另外,您为什么不只使用该方法中的 topLeft 点(没有所有这些 Math.Min)?

标签: silverlight xaml windows-phone-7 windows-phone-8 windows-phone


【解决方案1】:

我查看了它,但我找不到他们是如何隐藏 PivotItems 的。我猜这个位置是正确的,但是由于(对我而言)未知的原因,该项目没有被绘制。稍后我会再次研究它,但现在我想提一下我注意到的其他一些潜在问题。

  1. 您不应该在右下角使用 Math.Max 吗?原因是 - ActualHeight 和 ActualWidth 可以说是不支持旋转的。

  2. RenderSize.Width/Height 和 ActualWidth/Height 不同。我不确定将它们都用于计算是否是个好主意。

  3. 您不需要检查元素上方可视化树中的所有内容以查看它是否真的可见吗?

编辑:我查看了 Microsoft.Phone.dll 的反编译源(即带有 Pivot 控件的 dll),但找不到任何关于如何隐藏 PivotItems 的信息。不过也有一些本地方法调用。

【讨论】:

  • 感谢您的研究和积分。仍在考虑 1 和 2 - 我需要做一些原型设计来确认。在 3 上,这已经在我的“真实”代码中得到解决 - 它只是没有进入问题中的简单代码。
【解决方案2】:

我对您的代码及其赋予 UIElement 的真实位置进行了一些更改

XAML:

 <Grid x:Name="LayoutRoot" Background="Transparent">
        <!--Pivot Control-->
        <phone:Pivot x:Name="MyPivot">
            <phone:PivotItem Header="first" x:Name="first">
                <TextBlock x:Name="TB1" FontSize="30" Text="Hello 1" Tap="TB1_Tap"></TextBlock>
            </phone:PivotItem>

            <phone:PivotItem Header="second" x:Name="second">
                <TextBlock x:Name="TB2" FontSize="50" Height="66" Width="155" Margin="20" Text="Hello 2" Tap="TB2_Tap"></TextBlock>
            </phone:PivotItem>

            <phone:PivotItem Header="three" x:Name="three">
                <TextBlock x:Name="TB3" Text="Hello 3"></TextBlock>
            </phone:PivotItem>
        </phone:Pivot>
    </Grid>

CS:

public partial class PivotPage1 : PhoneApplicationPage

{
    public PivotPage1()
    {
        InitializeComponent();
    }
    private void TB1_Tap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        Rect r = Pos.MyPosition(TB1,first);
        string str = "Left" + r.Left.ToString() + "\nTop:" + r.Top.ToString() + "\nRight:" + r.Right.ToString() + "\nBottom:" + r.Bottom.ToString() + "\nHeight:" + r.Height.ToString() + "\nWidth" + r.Width.ToString();
        MessageBox.Show(str);
    }

    private void TB2_Tap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        Rect r = Pos.MyPosition(TB2,second);
        string str = "Left" + r.Left.ToString() + "\nTop:" + r.Top.ToString() + "\nRight:" + r.Right.ToString() + "\nBottom:" + r.Bottom.ToString() + "\nHeight:" + r.Height.ToString() + "\nWidth" + r.Width.ToString();
        MessageBox.Show(str);
    }
}

public static class Pos
{
    public static Rect MyPosition(FrameworkElement child,FrameworkElement parent)
    {
        if (child.Visibility == Visibility.Collapsed)
            return Rect.Empty;

    if (child.Opacity < 0.01)
        return Rect.Empty;

    // Obtain transform information based off root child
    GeneralTransform gt = child.TransformToVisual(parent);

    // Find the four corners of the child
    Point topLeft = gt.Transform(new Point(0, 0));
    Point topRight = gt.Transform(new Point(child.RenderSize.Width, 0));
    Point bottomLeft = gt.Transform(new Point(0, child.RenderSize.Height));
    Point bottomRight = gt.Transform(new Point(child.RenderSize.Width, child.RenderSize.Height));

    var left = Math.Min(Math.Min(Math.Min(topLeft.X, topRight.X), bottomLeft.X), bottomRight.X);
    var top = Math.Min(Math.Min(Math.Min(topLeft.Y, topRight.Y), bottomLeft.Y), bottomRight.Y);
    var position = new Rect(left, top, child.ActualWidth, child.ActualHeight);

    return position;
    }
}

【讨论】:

  • 谢谢。除了更改父级之外,我在您的代码中看不到任何其他差异-我缺少什么吗?另外,澄清一下:当点击TB2 时,我希望得到TB1 相对于屏幕正确报告的位置。目前,问题中的代码报告 TB1 位于“屏幕上”位置,而 TB1 确实应该在屏幕一侧的某处。
猜你喜欢
  • 2015-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多