0

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

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,也不考虑它。FindElementsInHostCoordinatesincludeAllElementstrue

根据文档,如果我将参数设置includeAllElementstrue,它应该会找到所有元素,包括那些IsHitTestVisible设置为的控件false

includeAllElements [System.Boolean]

true 包括所有相交的元素,包括那些被认为对命中测试不可见的元素。false 仅查找可见的、可命中测试的元素。默认值为假。

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

4

2 回答 2

1

@ZORRO的观察基本上是正确的。

XAML 命中测试基于这样的理念:如果一个元素占据屏幕上的空间并“产生墨迹”,那么它就会进行命中测试。

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

  • 对于具有Brush(绝大多数)的元素,任何非空画笔都被认为会产生 ink,即使画笔不会产生可见像素。例如SolidColorBrush颜色为“透明”的仍会产生 ink只有零画笔不会产生墨水

  • 有一些特殊的元素,例如SwapChainPanelMediaElement,它们没有刷子但仍然可以产生墨水

  • 此处不考虑 Opacity 属性

因此,只要上述之一为真,即使不透明度等于 0 ,该元素仍会产生墨迹。

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

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

于 2017-02-27T05:51:34.543 回答
0

我认为这个问题的关键是什么是“被认为对命中测试不可见的元素”。

我认为当我们设置IsHitTestVisible为时false,该元素不被认为是不可见的,它只是不可见的。并且根据命中测试和输入事件,满足以下条件的元素是可命中测试的。

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

所以我认为当一个元素的Visibility属性值为Collapsedor its Backgroundor Fillproperty value is nullor its IsEnabledproperty value isfalse时,该元素被认为是不可见的。我做了一个简单的测试。

<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时才生效。不确定这是否是设计使然。也许只有其属性值被认为是不可见的元素。BackgroundFillnullBackgroundFillnull

于 2017-02-18T11:39:04.060 回答