Browse Source

Fix - Search for visual parents when hittesting for pointer events (#18416)

* search for visual parents when hittesting

* Add unit test for hit testing on disabled visual

---------

Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
pull/18430/head
Emmanuel Hansen 11 months ago
committed by GitHub
parent
commit
e189ef9c53
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/Avalonia.Controls/TopLevel.cs
  2. 55
      tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs

2
src/Avalonia.Controls/TopLevel.cs

@ -866,7 +866,7 @@ namespace Avalonia.Controls
var candidate = hitTestElement;
while (candidate?.IsEffectivelyEnabled == false)
{
candidate = (candidate as Visual)?.Parent as IInputElement;
candidate = (candidate as Visual)?.VisualParent as IInputElement;
}
return candidate;

55
tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs

@ -6,6 +6,7 @@ using Avalonia.Controls;
using Avalonia.Headless;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Media;
using Avalonia.Rendering;
using Avalonia.UnitTests;
@ -494,6 +495,60 @@ namespace Avalonia.Base.UnitTests.Input
result);
}
[Fact]
public void Disabled_Element_Should_Set_PointerOver_On_Visual_Parent()
{
using var app = UnitTestApplication.Start(new TestServices(inputManager: new InputManager()));
var renderer = new Mock<IHitTester>();
var deviceMock = CreatePointerDeviceMock();
var impl = CreateTopLevelImplMock();
var disabledChild = new Border
{
Background = Brushes.Red,
Width = 100,
Height = 100,
IsEnabled = false
};
var visualParent = new Border
{
Background = Brushes.Black,
Width = 100,
Height = 100,
Child = disabledChild
};
var logicalParent = new Border
{
Background = Brushes.Blue,
Width = 100,
Height = 100
};
// Change the logical parent and check that we're correctly hit testing on the visual tree.
// This scenario is made up because it's easy to test.
// In the real world, this happens with nested Popups from MenuItems (but that's very cumbersome to test).
((ISetLogicalParent) disabledChild).SetParent(null);
((ISetLogicalParent) disabledChild).SetParent(logicalParent);
var root = CreateInputRoot(
impl.Object,
new Panel
{
Children = { visualParent }
},
renderer.Object);
Assert.False(visualParent.IsPointerOver);
SetHit(renderer, disabledChild);
impl.Object.Input!(CreateRawPointerMovedArgs(deviceMock.Object, root, new Point(50, 50)));
Assert.True(visualParent.IsPointerOver);
Assert.False(logicalParent.IsPointerOver);
}
private static void AddEnteredExitedHandlers(
EventHandler<PointerEventArgs> handler,
params IInputElement[] controls)

Loading…
Cancel
Save