diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index 7434bd6cc1..14beb2eab7 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -656,7 +656,6 @@ namespace Avalonia.Controls
/// The event args.
protected virtual void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
- AttachedToLogicalTree?.Invoke(this, e);
}
///
@@ -665,7 +664,6 @@ namespace Avalonia.Controls
/// The event args.
protected virtual void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
- DetachedFromLogicalTree?.Invoke(this, e);
}
///
@@ -842,6 +840,7 @@ namespace Avalonia.Controls
InitializeStylesIfNeeded(true);
OnAttachedToLogicalTree(e);
+ AttachedToLogicalTree?.Invoke(this, e);
}
foreach (var child in LogicalChildren.OfType())
@@ -862,6 +861,7 @@ namespace Avalonia.Controls
_isAttachedToLogicalTree = false;
_styleDetach.OnNext(this);
OnDetachedFromLogicalTree(e);
+ DetachedFromLogicalTree?.Invoke(this, e);
foreach (var child in LogicalChildren.OfType())
{
diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs
index 875a5ebaee..50cdb5945c 100644
--- a/src/Avalonia.Input/MouseDevice.cs
+++ b/src/Avalonia.Input/MouseDevice.cs
@@ -20,6 +20,8 @@ namespace Avalonia.Input
private int _clickCount;
private Rect _lastClickRect;
private uint _lastClickTime;
+ private IInputElement _captured;
+ private IDisposable _capturedSubscription;
///
/// Gets the control that is currently capturing by the mouse, if any.
@@ -31,8 +33,23 @@ namespace Avalonia.Input
///
public IInputElement Captured
{
- get;
- protected set;
+ get => _captured;
+ protected set
+ {
+ _capturedSubscription?.Dispose();
+ _capturedSubscription = null;
+
+ if (value != null)
+ {
+ _capturedSubscription = Observable.FromEventPattern(
+ x => value.DetachedFromVisualTree += x,
+ x => value.DetachedFromVisualTree -= x)
+ .Take(1)
+ .Subscribe(_ => Captured = null);
+ }
+
+ _captured = value;
+ }
}
///
@@ -55,6 +72,7 @@ namespace Avalonia.Input
///
public virtual void Capture(IInputElement control)
{
+ // TODO: Check visibility and enabled state before setting capture.
Captured = control;
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
index a85fd36763..a4af106a73 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
@@ -173,7 +173,7 @@ namespace Avalonia.Rendering.SceneGraph
}
}
- if (node.HitTest(p))
+ if (node.HitTest(p) && node.Visual.IsAttachedToVisualTree)
{
yield return node.Visual;
}
diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs
index cfe6bce7e0..bc65d4f69f 100644
--- a/src/Avalonia.Visuals/Visual.cs
+++ b/src/Avalonia.Visuals/Visual.cs
@@ -329,6 +329,7 @@ namespace Avalonia
}
OnAttachedToVisualTree(e);
+ AttachedToVisualTree?.Invoke(this, e);
InvalidateVisual();
if (VisualChildren != null)
@@ -357,6 +358,7 @@ namespace Avalonia
}
OnDetachedFromVisualTree(e);
+ DetachedFromVisualTree?.Invoke(this, e);
e.Root?.Renderer?.AddDirty(this);
if (VisualChildren != null)
@@ -374,7 +376,6 @@ namespace Avalonia
/// The event args.
protected virtual void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
- AttachedToVisualTree?.Invoke(this, e);
}
///
@@ -383,7 +384,6 @@ namespace Avalonia
/// The event args.
protected virtual void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
- DetachedFromVisualTree?.Invoke(this, e);
}
///
diff --git a/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs b/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs
index 4a834fd55d..6aca69b88f 100644
--- a/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs
+++ b/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs
@@ -1,6 +1,5 @@
using Avalonia.Controls;
using Avalonia.Input.Raw;
-using Avalonia.Layout;
using Avalonia.Rendering;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
@@ -12,6 +11,24 @@ namespace Avalonia.Input.UnitTests
{
public class MouseDeviceTests
{
+ [Fact]
+ public void Capture_Is_Cleared_When_Control_Removed()
+ {
+ Canvas control;
+ var root = new TestRoot
+ {
+ Child = control = new Canvas(),
+ };
+ var target = new MouseDevice();
+
+ target.Capture(control);
+ Assert.Same(control, target.Captured);
+
+ root.Child = null;
+
+ Assert.Null(target.Captured);
+ }
+
[Fact]
public void MouseMove_Should_Update_PointerOver()
{