diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml index b3f32ed421..eeb198976b 100644 --- a/samples/ControlCatalog/Pages/SliderPage.xaml +++ b/samples/ControlCatalog/Pages/SliderPage.xaml @@ -22,6 +22,20 @@ IsSnapToTickEnabled="True" Ticks="0,20,25,40,75,100" Width="300" /> + + + + + ToolTip A control which pops up a hint when a control is hovered - @@ -38,6 +38,31 @@ ToolTip bottom placement + + + + + Moving offset + diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs index 71bd0726d4..ab507d07a2 100644 --- a/src/Avalonia.Controls/ToolTip.cs +++ b/src/Avalonia.Controls/ToolTip.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Reactive.Linq; using Avalonia.Controls.Metadata; @@ -21,8 +22,8 @@ namespace Avalonia.Controls /// /// Defines the ToolTip.Tip attached property. /// - public static readonly AttachedProperty TipProperty = - AvaloniaProperty.RegisterAttached("Tip"); + public static readonly AttachedProperty TipProperty = + AvaloniaProperty.RegisterAttached("Tip"); /// /// Defines the ToolTip.IsOpen attached property. @@ -57,10 +58,10 @@ namespace Avalonia.Controls /// /// Stores the current instance in the control. /// - internal static readonly AttachedProperty ToolTipProperty = - AvaloniaProperty.RegisterAttached("ToolTip"); + internal static readonly AttachedProperty ToolTipProperty = + AvaloniaProperty.RegisterAttached("ToolTip"); - private IPopupHost _popup; + private IPopupHost? _popup; /// /// Initializes static members of the class. @@ -70,6 +71,10 @@ namespace Avalonia.Controls TipProperty.Changed.Subscribe(ToolTipService.Instance.TipChanged); IsOpenProperty.Changed.Subscribe(ToolTipService.Instance.TipOpenChanged); IsOpenProperty.Changed.Subscribe(IsOpenChanged); + + HorizontalOffsetProperty.Changed.Subscribe(RecalculatePositionOnPropertyChanged); + VerticalOffsetProperty.Changed.Subscribe(RecalculatePositionOnPropertyChanged); + PlacementProperty.Changed.Subscribe(RecalculatePositionOnPropertyChanged); } /// @@ -79,7 +84,7 @@ namespace Avalonia.Controls /// /// The content to be displayed in the control's tooltip. /// - public static object GetTip(Control element) + public static object? GetTip(Control element) { return element.GetValue(TipProperty); } @@ -89,7 +94,7 @@ namespace Avalonia.Controls /// /// The control to get the property from. /// The content to be displayed in the control's tooltip. - public static void SetTip(Control element, object value) + public static void SetTip(Control element, object? value) { element.SetValue(TipProperty, value); } @@ -207,8 +212,8 @@ namespace Avalonia.Controls private static void IsOpenChanged(AvaloniaPropertyChangedEventArgs e) { var control = (Control)e.Sender; - var newValue = (bool)e.NewValue; - ToolTip toolTip; + var newValue = (bool)e.NewValue!; + ToolTip? toolTip; if (newValue) { @@ -235,6 +240,23 @@ namespace Avalonia.Controls toolTip?.UpdatePseudoClasses(newValue); } + private static void RecalculatePositionOnPropertyChanged(AvaloniaPropertyChangedEventArgs args) + { + var control = (Control)args.Sender; + var tooltip = control.GetValue(ToolTipProperty); + if (tooltip == null) + { + return; + } + + tooltip.RecalculatePosition(control); + } + + internal void RecalculatePosition(Control control) + { + _popup?.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control))); + } + private void Open(Control control) { Close(); diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs index 341ab2fe81..9e0bf60f42 100644 --- a/src/Avalonia.Controls/ToolTipService.cs +++ b/src/Avalonia.Controls/ToolTipService.cs @@ -51,10 +51,12 @@ namespace Avalonia.Controls if (e.OldValue is false && e.NewValue is true) { control.DetachedFromVisualTree += ControlDetaching; + control.EffectiveViewportChanged += ControlEffectiveViewportChanged; } else if(e.OldValue is true && e.NewValue is false) { control.DetachedFromVisualTree -= ControlDetaching; + control.EffectiveViewportChanged -= ControlEffectiveViewportChanged; } } @@ -62,6 +64,7 @@ namespace Avalonia.Controls { var control = (Control)sender; control.DetachedFromVisualTree -= ControlDetaching; + control.EffectiveViewportChanged -= ControlEffectiveViewportChanged; Close(control); } @@ -97,6 +100,13 @@ namespace Avalonia.Controls Close(control); } + private void ControlEffectiveViewportChanged(object sender, Layout.EffectiveViewportChangedEventArgs e) + { + var control = (Control)sender; + var toolTip = control.GetValue(ToolTip.ToolTipProperty); + toolTip?.RecalculatePosition(control); + } + private void StartShowTimer(int showDelay, Control control) { _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(showDelay) };