Browse Source

Clear mouse capture when control removed.

When a captured control is removed from the visual tree, clear the mouse capture.

Note that our capture logic needs to be improved - it shouldn't be possible to capture a non-visible or non-enabled control. This doesn't address that but it does fix the crash in #1203.

Fixes #1203
pull/1210/head
Steven Kirk 9 years ago
parent
commit
763775fa82
  1. 22
      src/Avalonia.Input/MouseDevice.cs
  2. 19
      tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs

22
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;
/// <summary>
/// Gets the control that is currently capturing by the mouse, if any.
@ -31,8 +33,23 @@ namespace Avalonia.Input
/// </remarks>
public IInputElement Captured
{
get;
protected set;
get => _captured;
protected set
{
_capturedSubscription?.Dispose();
_capturedSubscription = null;
if (value != null)
{
_capturedSubscription = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => value.DetachedFromVisualTree += x,
x => value.DetachedFromVisualTree -= x)
.Take(1)
.Subscribe(_ => Captured = null);
}
_captured = value;
}
}
/// <summary>
@ -55,6 +72,7 @@ namespace Avalonia.Input
/// </remarks>
public virtual void Capture(IInputElement control)
{
// TODO: Check visibility and enabled state before setting capture.
Captured = control;
}

19
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()
{

Loading…
Cancel
Save