diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs index b458b15c64..cf0652247f 100644 --- a/src/Avalonia.Controls/ToolTip.cs +++ b/src/Avalonia.Controls/ToolTip.cs @@ -66,6 +66,7 @@ namespace Avalonia.Controls static ToolTip() { TipProperty.Changed.Subscribe(ToolTipService.Instance.TipChanged); + IsOpenProperty.Changed.Subscribe(ToolTipService.Instance.TipOpenChanged); IsOpenProperty.Changed.Subscribe(IsOpenChanged); } diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs index 569697304f..e2a0f9e50c 100644 --- a/src/Avalonia.Controls/ToolTipService.cs +++ b/src/Avalonia.Controls/ToolTipService.cs @@ -28,20 +28,33 @@ namespace Avalonia.Controls { control.PointerEnter -= ControlPointerEnter; control.PointerLeave -= ControlPointerLeave; - control.DetachedFromVisualTree -= ControlDetaching; } if (e.NewValue != null) { control.PointerEnter += ControlPointerEnter; control.PointerLeave += ControlPointerLeave; + } + } + + internal void TipOpenChanged(AvaloniaPropertyChangedEventArgs e) + { + var control = (Control)e.Sender; + + if (e.OldValue is false && e.NewValue is true) + { control.DetachedFromVisualTree += ControlDetaching; } + else if(e.OldValue is true && e.NewValue is false) + { + control.DetachedFromVisualTree -= ControlDetaching; + } } private void ControlDetaching(object sender, VisualTreeAttachmentEventArgs e) { var control = (Control)sender; + control.DetachedFromVisualTree -= ControlDetaching; Close(control); } diff --git a/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs b/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs index 9d7bc6af74..e52e7a487b 100644 --- a/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs @@ -1,5 +1,6 @@ using System; using System.Reactive.Disposables; +using Avalonia.Markup.Xaml; using Avalonia.Platform; using Avalonia.Threading; using Avalonia.UnitTests; @@ -64,6 +65,39 @@ namespace Avalonia.Controls.UnitTests Assert.False(ToolTip.GetIsOpen(target)); } } + + [Fact] + public void Should_Close_When_Tip_Is_Opened_And_Detached_From_Visual_Tree() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + + window.DataContext = new ToolTipViewModel(); + window.ApplyTemplate(); + window.Presenter.ApplyTemplate(); + + var target = window.Find("PART_target"); + var panel = window.Find("PART_panel"); + + Assert.True((target as IVisual).IsAttachedToVisualTree); + + _mouseHelper.Enter(target); + + Assert.True(ToolTip.GetIsOpen(target)); + + panel.Children.Remove(target); + + Assert.False(ToolTip.GetIsOpen(target)); + } + } [Fact] public void Should_Open_On_Pointer_Enter() @@ -208,4 +242,9 @@ namespace Avalonia.Controls.UnitTests } } } + + internal class ToolTipViewModel + { + public string Tip => "Tip"; + } }