VisualTreeHelper.FindElementsInHostCoordinates不会返回IsHitTestVisible设置为false的控件

时间:2017-02-09 09:59:55

标签: c# wpf xaml uwp visualtreehelper

我正在做一些实验,我正在尝试收集放在鼠标指针下的所有元素。

XAML测试代码

<StackPanel>
    <Button
        x:Name="HitButton"
        Content="Test Button" />
    <Button
        x:Name="NotHitButton"
        IsHitTestVisible="False"
        Content="Test Button" />
</StackPanel>

要获取鼠标指针的坐标,请使用PointerMoved

CoreWindow.GetForCurrentThread().PointerMoved += OnPointerMoved;

private void OnPointerMoved(CoreWindow sender, PointerEventArgs args)
{
    Point point = args.CurrentPoint.Position;
    IEnumerable<UIElement> elements = VisualTreeHelper.FindElementsInHostCoordinates(point, null, true);
    ...
}

但是,当控件的属性IsHitTestVisible设置为false时,此方法有效,即使我设置了第三个参数FindElementsInHostCoordinatesincludeAllElements也不会考虑它这种方法对true

根据documentation我希望如果我将参数includeAllElements设置为true,它应该找到所有元素,包括IsHitTestVisible设置为{的那些控件{1}}。

  

includeAllElements [System.Boolean]

     

如果包含所有元素,则为true   相交,包括那些被认为是不可见的元素   测试。 false仅查找可见的,可命中的元素。该   默认为false。

我是否理解false如何运作的错误方式?如果是这样,即使他们将FindElementsInHostCoordinates设置为IsHitTestVisible,还有其他方法可以检索特定坐标处的所有控件吗?

2 个答案:

答案 0 :(得分:1)

@ZORRO的观察结果大多正确。

XAML命中测试基于如下理念:如果元素占据屏幕上的空间并且&#34; 生成墨迹 &#34;然后它进行了测试。

主要问题是围绕什么产生墨水:

  • 对于Brush(绝大多数)的元素,任何非空画笔都被视为生成墨迹的内容,即使画笔不会产生可见像素。例如 a SolidColorBrush,颜色为&#34;透明&#34; 仍会生成墨迹 只有空画笔不会产生墨迹

  • 有一些特殊元素,例如SwapChainPanelMediaElement没有画笔,但 仍然可以生成墨迹

  • 此处不考虑不透明度属性

因此只要上述之一为真,即使Opacity等于0,元素仍会产生墨水

这一切意味着当includeAllElements参数设置为true时,不会产生墨水的元素会被视为进行点击测试。在这种情况下,只要元素满足空间要求(点/矩形与元素边界相交),那么它及其祖先就会包含在结果中。

顺便说一句,我们正在与内容团队合作,以完善此文档,以便明确。

答案 1 :(得分:0)

我认为这个问题的关键点是什么是“被认为是不可见才能进行测试”。

我认为当我们将IsHitTestVisible设置为false时,该元素不会被视为不可见,它只是不可见。根据{{​​3}},元素符合以下条件是可以测试的。

  
      
  • 元素的可见性属性值为可见
  •   
  • 元素的背景填充属性值不为空。 null Brush 值会导致透明度和命中测试不可见性。 (要使元素透明但也可以测试,请使用透明画笔而不是 null 。)
  •   
  • 如果元素是控件,则其 IsEnabled 属性值必须为 true
  •   
  • 元素在布局中必须具有实际尺寸。 ActualHeight ActualWidth 为0的元素不会触发输入事件。
  •   

所以我认为当元素的Visibility属性值为Collapsed或其BackgroundFill属性值为null或其IsEnabled时属性值为false,该元素被视为不可见。我做了一个简单的测试。

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Border Name="Border" Width="200" Height="300" BorderThickness="1" BorderBrush="Black" Background="AliceBlue">
        <Grid Name="Grid" Width="100" Height="250">
            <Rectangle Name="CollapsedRectangle" Fill="Azure" Visibility="Collapsed" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top" />
            <Rectangle Name="NoFillRectangle" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,100,0,0" />
            <Button Name="Button" IsEnabled="False" VerticalAlignment="Top" Margin="0,200,0,0">CLICK</Button>
        </Grid>
    </Border>
</Grid>

public MainPage()
{
    this.InitializeComponent();
    CoreWindow.GetForCurrentThread().PointerMoved += (s, e) =>
    {
        Point point = e.CurrentPoint.Position;
        IEnumerable<UIElement> elements = VisualTreeHelper.FindElementsInHostCoordinates(point, Border, false);

        foreach (var item in elements)
        {
            FrameworkElement feItem = item as FrameworkElement;
            System.Diagnostics.Debug.WriteLine(feItem.Name);
        }

        System.Diagnostics.Debug.WriteLine("-----------------------------------------");
    };
}

includeAllElements参数设置为false时,输出类似于

Border
-----------------------------------------
Border
-----------------------------------------
Border
-----------------------------------------

includeAllElements参数设置为true时,输出就像

Border
-----------------------------------------
Grid
Border
-----------------------------------------
...
NoFillRectangle
Grid
Border
-----------------------------------------
...
Grid
Border
-----------------------------------------
Border
-----------------------------------------

因此,includeAllElements参数似乎仅在元素的BackgroundFill属性值为null时生效。不确定这是否符合设计要求。 可能只有BackgroundFill属性值为null的元素才被视为不可见。