如何检测控件是否在屏幕上可见?

时间:2014-03-15 17:22:18

标签: c# xaml windows-phone-8 windows-phone panorama-control

我有一个Panorama控件,它有三个项目:

<phone:Panorama>

    <phone:PanoramaItem>

    </phone:PanoramaItem>

    <phone:PanoramaItem>

    </phone:PanoramaItem>

    <phone:PanoramaItem Header="third item" Orientation="Horizontal">
        <Grid>
            <StackPanel Margin="0,4,16,0" Orientation="Vertical" VerticalAlignment="Top">
                <StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                </StackPanel>
                <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,12,0,0">
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="Black" Height="173" Width="173" Margin="12,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </Grid>
    </phone:PanoramaItem>
</phone:Panorama>

我怎么知道屏幕上是否有用户可见的带有黑色背景的最后Border?因为它是水平PanoramaItem,所以我不能依赖全景SelectedIndex。任何提示?

1 个答案:

答案 0 :(得分:2)

如果您只想检查一个元素是否在屏幕范围内,您可以像这样使用VisualTreeHelper:

Rect screenBounds = new Rect(0, 0, Application.Current.Host.Content.ActualWidth, Application.Current.Host.Content.ActualHeight);

if (VisualTreeHelper.FindElementsInHostCoordinates(screenBounds, myPanorama).Contains(elementToCheck))
    Debug.WriteLine("Element is now visible");
else
    Debug.WriteLine("Element is no longer visible");

我对XAML进行了两处更改(仅为了简化示例),首先我命名为Panorama

<phone:Panorama x:Name="myPanorama">

其次,我还将Border元素命名为您要检查的可见性:

<Border x:Name="elementToCheck" Background="Black" Height="173" Width="173" Margin="12,0,0,0"/>

如果您还希望在全景滚动更改时在事件中检查它,则似乎变得更难,因为如果控件位于其他控件之下,则ManipulationDelta事件不起作用。一种解决方案是每次报告触摸的fram时进行检查。这是通过以下方式完成的:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    Touch.FrameReported += Touch_FrameReported;
}

private void Touch_FrameReported(object sender, TouchFrameEventArgs e)
{
    // This is the same code as above
    Rect screenBounds = new Rect(0, 0, Application.Current.Host.Content.ActualWidth, Application.Current.Host.Content.ActualHeight);

    if (VisualTreeHelper.FindElementsInHostCoordinates(screenBounds, myPanorama).Contains(elementToCheck))
        Debug.WriteLine("Element is now visible");
    else
        Debug.WriteLine("Element is no longer visible");
}

对于VisualTreeHelperTouch

,您还需要使用这两个指令
using System.Windows.Media;
using System.Windows.Input;

不幸的是,我现在无法想到更简单的解决方案。

修改 这个事件远非完美,例如,如果全景被淘汰&#34;以编程方式或当它捕捉时它不会给出预期的结果。问题是全景图基于PanningLayerPanningTitleLayerPanningBackgroundLayer而不是ScrollViewer构建,因此没有ScrollBar,这意味着没有Scroll event:(

一种解决方案是使用计时器定期检查它是否可见,但这也感觉就像一个丑陋的解决方案。