瀏覽代碼

Do not recapture already captured element (#19740)

* Do not recapture already captured element

* Recapture tests

---------

Co-authored-by: Jan Kučera <[email protected]>
Jan Kučera 2 周之前
父節點
當前提交
aadcd01d55

+ 5 - 2
src/Avalonia.Base/Input/Pointer.cs

@@ -46,9 +46,12 @@ namespace Avalonia.Input
 
         private void Capture(IInputElement? control, bool platformInitiated)
         {
-            if (Captured is Visual v1)
-                v1.DetachedFromVisualTree -= OnCaptureDetached;
             var oldCapture = Captured;
+            if (oldCapture == control)
+                return;
+
+            if (oldCapture is Visual v1)
+                v1.DetachedFromVisualTree -= OnCaptureDetached;
             Captured = control;
             
             if (!platformInitiated)

+ 17 - 0
tests/Avalonia.Base.UnitTests/Input/PointerTests.cs

@@ -36,5 +36,22 @@ namespace Avalonia.Base.UnitTests.Input
             pointer.Capture(null);
             Assert.True(receivers.SequenceEqual(new object[] { newCapture, newParent, el, root }));
         }
+
+        [Fact]
+        public void Capture_Captured_ShouldNot_Call_Platform()
+        {
+            var pointer = new TestPointer(Pointer.GetNextFreeId(), PointerType.Mouse, true);
+
+            Border capture = new Border();
+            pointer.Capture(capture);
+            pointer.Capture(capture);
+
+            Assert.Equal(1, pointer.PlatformCaptureCalled);
+
+            pointer.Capture(null);
+            pointer.Capture(null);
+
+            Assert.Equal(2, pointer.PlatformCaptureCalled);
+        }
     }
 }

+ 12 - 0
tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs

@@ -16,6 +16,18 @@ namespace Avalonia.Base.UnitTests.Input;
 
 public abstract class PointerTestsBase : ScopedTestBase
 {
+    protected class TestPointer : Pointer
+    {
+        internal int PlatformCaptureCalled = 0;
+
+        internal TestPointer(int id, PointerType type, bool isPrimary) : base(id, type, isPrimary) { }
+
+        protected override void PlatformCapture(IInputElement? element)
+        {
+            PlatformCaptureCalled++;
+        }
+    }
+
     private protected static void SetHit(Mock<IHitTester> renderer, Control? hit)
     {
         renderer.Setup(x => x.HitTest(It.IsAny<Point>(), It.IsAny<Visual>(), It.IsAny<Func<Visual, bool>>()))