VisualTreeHelper.FindElementsInHostCoordinates 不 return 控制 IsHitTestVisible 设置为 false
VisualTreeHelper.FindElementsInHostCoordinates does not return controls with IsHitTestVisible set up to false
我正在做一些实验,我正在尝试收集所有放置在鼠标指针下的元素。
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
时,即使我设置了第三个 FindElementsInHostCoordinates
也不会考虑它此方法的参数 includeAllElements
为 true
.
根据 documentation 我希望如果我将参数 includeAllElements
设置为 true
,它应该找到所有元素,包括那些设置了 IsHitTestVisible
的控件至 false
.
includeAllElements [System.Boolean]
true to include all elements that
intersect, including those elements considered to be invisible to hit
testing. false to find only visible, hit-testable elements. The
default is false.
我对 FindElementsInHostCoordinates
工作方式的理解有误吗?如果是这样,有没有其他方法如何检索特定坐标处的所有控件,即使它们将 IsHitTestVisible
设置为 false
?
我认为这个问题的关键点是什么是 "elements considered to be invisible to hit testing"。
我认为当我们将 IsHitTestVisible
设置为 false
时,该元素不被认为是不可见的,它只是不可见的。而根据Hit testing and input events,满足以下条件的元素是hit-testable.
- The element's Visibility property value is Visible.
- The element's Background or Fill property value is not null. A null Brush value results in transparency and hit test invisibility. (To make an element transparent but also hit testable, use a Transparent brush instead of null.)
- If the element is a control, its IsEnabled property value must be true.
- The element must have actual dimensions in layout. An element where either ActualHeight and ActualWidth are 0 won't fire input events.
所以我认为当一个元素的 Visibility
属性 值是 Collapsed
或者它的 Background
或 Fill
属性 值是 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
参数只有在元素的Background
或Fill
属性值为null
时才会生效。不确定这是否是设计使然。 可能只有 Background
或 Fill
属性 值为 null
的元素被认为是不可见的。
的观察基本正确。
XAML 命中测试基于以下理念:如果元素在屏幕上占据 space 并且“ 产生墨迹" 然后它命中测试。
主要问题是什么产生墨水:
对于具有 Brush
(绝大多数)的元素,任何 非空 笔刷都被认为是 产生墨水 ,即使画笔不产生可见像素。例如 a SolidColorBrush
颜色 "Transparent" 仍然产生墨水 。 只有空刷不出墨.
有一些特殊元素如SwapChainPanel
和MediaElement
没有刷子但可以仍然产生墨水.
这里不考虑Opacity 属性
因此,只要满足上述条件之一,即使不透明度等于 0,元素 仍会产生墨水。
这意味着当 includeAllElements
参数设置为 true 时,不产生墨水的元素 将被考虑用于命中测试。在这种情况下,只要元素满足空间要求(point/rect 与元素边界相交),那么它和它的祖先都包含在结果中。
顺便说一句,我们正在与内容团队合作以完善此文档以使其更加清晰。
我正在做一些实验,我正在尝试收集所有放置在鼠标指针下的元素。
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
时,即使我设置了第三个 FindElementsInHostCoordinates
也不会考虑它此方法的参数 includeAllElements
为 true
.
根据 documentation 我希望如果我将参数 includeAllElements
设置为 true
,它应该找到所有元素,包括那些设置了 IsHitTestVisible
的控件至 false
.
includeAllElements [System.Boolean]
true to include all elements that intersect, including those elements considered to be invisible to hit testing. false to find only visible, hit-testable elements. The default is false.
我对 FindElementsInHostCoordinates
工作方式的理解有误吗?如果是这样,有没有其他方法如何检索特定坐标处的所有控件,即使它们将 IsHitTestVisible
设置为 false
?
我认为这个问题的关键点是什么是 "elements considered to be invisible to hit testing"。
我认为当我们将 IsHitTestVisible
设置为 false
时,该元素不被认为是不可见的,它只是不可见的。而根据Hit testing and input events,满足以下条件的元素是hit-testable.
- The element's Visibility property value is Visible.
- The element's Background or Fill property value is not null. A null Brush value results in transparency and hit test invisibility. (To make an element transparent but also hit testable, use a Transparent brush instead of null.)
- If the element is a control, its IsEnabled property value must be true.
- The element must have actual dimensions in layout. An element where either ActualHeight and ActualWidth are 0 won't fire input events.
所以我认为当一个元素的 Visibility
属性 值是 Collapsed
或者它的 Background
或 Fill
属性 值是 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
参数只有在元素的Background
或Fill
属性值为null
时才会生效。不确定这是否是设计使然。 可能只有 Background
或 Fill
属性 值为 null
的元素被认为是不可见的。
XAML 命中测试基于以下理念:如果元素在屏幕上占据 space 并且“ 产生墨迹" 然后它命中测试。
主要问题是什么产生墨水:
对于具有
Brush
(绝大多数)的元素,任何 非空 笔刷都被认为是 产生墨水 ,即使画笔不产生可见像素。例如 aSolidColorBrush
颜色 "Transparent" 仍然产生墨水 。 只有空刷不出墨.有一些特殊元素如
SwapChainPanel
和MediaElement
没有刷子但可以仍然产生墨水.这里不考虑Opacity 属性
因此,只要满足上述条件之一,即使不透明度等于 0,元素 仍会产生墨水。
这意味着当 includeAllElements
参数设置为 true 时,不产生墨水的元素 将被考虑用于命中测试。在这种情况下,只要元素满足空间要求(point/rect 与元素边界相交),那么它和它的祖先都包含在结果中。
顺便说一句,我们正在与内容团队合作以完善此文档以使其更加清晰。