Skip to content

Commit

Permalink
fix: ToolTip implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Xiaoy312 committed Jul 10, 2021
1 parent d0ce51a commit 5583919
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Windows.UI.Xaml.Controls
#endif
public partial class ToolTipService
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public static global::Windows.UI.Xaml.DependencyProperty PlacementProperty { get; } =
Windows.UI.Xaml.DependencyProperty.RegisterAttached(
Expand All @@ -25,14 +25,14 @@ public partial class ToolTipService
#endif
// Skipping already declared property ToolTipProperty
// Forced skipping of method Windows.UI.Xaml.Controls.ToolTipService.PlacementProperty.get
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public static global::Windows.UI.Xaml.Controls.Primitives.PlacementMode GetPlacement( global::Windows.UI.Xaml.DependencyObject element)
{
return (global::Windows.UI.Xaml.Controls.Primitives.PlacementMode)element.GetValue(PlacementProperty);
}
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public static void SetPlacement( global::Windows.UI.Xaml.DependencyObject element, global::Windows.UI.Xaml.Controls.Primitives.PlacementMode value)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/ToolTip/ToolTip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ internal Popup Popup
}
}

internal long CurrentHoverId { get; set; }

internal IDisposable _pointerEventSubscriptions;

#pragma warning disable CS0649
#pragma warning disable CS0169
#pragma warning disable CS0414
Expand Down
181 changes: 134 additions & 47 deletions src/Uno.UI/UI/Xaml/Controls/ToolTip/ToolTipService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,53 @@
using System.Threading.Tasks;
using Windows.UI.Xaml.Input;
using Uno.UI;
using Windows.UI.Xaml.Controls.Primitives;
using Uno.Disposables;

namespace Windows.UI.Xaml.Controls
{
partial class ToolTipService
{
#region DependencyProperty: ToolTip

public static DependencyProperty ToolTipProperty { get; } =
DependencyProperty.RegisterAttached(
"ToolTip",
typeof(object),
typeof(ToolTipService),
new FrameworkPropertyMetadata(default, OnToolTipChanged));

public static object GetToolTip(DependencyObject element)
{
return element.GetValue(ToolTipProperty);
}
public static object GetToolTip(DependencyObject obj) => obj.GetValue(ToolTipProperty);
public static void SetToolTip(DependencyObject obj, object value) => obj.SetValue(ToolTipProperty, value);

public static void SetToolTip( global::Windows.UI.Xaml.DependencyObject element, object value)
{
element.SetValue(ToolTipProperty, value);
}
#endregion
#region DependencyProperty: Placement

public static DependencyProperty PlacementProperty { get; } = DependencyProperty.RegisterAttached(
"Placement",
typeof(PlacementMode),
typeof(ToolTipService),
new PropertyMetadata(PlacementMode.Top, OnPlacementChanged));

public static PlacementMode GetPlacement(FrameworkElement obj) => (PlacementMode)obj.GetValue(PlacementProperty);
public static void SetPlacement(FrameworkElement obj, PlacementMode value) => obj.SetValue(PlacementProperty, value);

private static void OnToolTipChanged(DependencyObject dependencyobject, DependencyPropertyChangedEventArgs args)
#endregion
#region DependencyProperty: ToolTipReference

internal static DependencyProperty ToolTipReferenceProperty { get; } = DependencyProperty.RegisterAttached(
"ToolTipReference",
typeof(ToolTip),
typeof(ToolTipService),
new PropertyMetadata(default(ToolTip)));

internal static ToolTip GetToolTipReference(DependencyObject obj) => (ToolTip)obj.GetValue(ToolTipReferenceProperty);
internal static void SetToolTipReference(DependencyObject obj, ToolTip value) => obj.SetValue(ToolTipReferenceProperty, value);

#endregion


private static void OnToolTipChanged(DependencyObject dependencyobject, DependencyPropertyChangedEventArgs e)
{
if (!FeatureConfiguration.ToolTip.UseToolTips)
{
Expand All @@ -36,62 +60,125 @@ private static void OnToolTipChanged(DependencyObject dependencyobject, Dependen
return;
}

var toolTip = args.NewValue as ToolTip;
if (e.NewValue is null)
{
DisposePreviousToolTip();
}
else if (e.NewValue is ToolTip newToolTip)
{
var previousToolTip = GetToolTipReference(element);

// dispose the previous tooltip
if (previousToolTip != null && newToolTip != previousToolTip)
{
DisposePreviousToolTip(previousToolTip);
}

if (toolTip == null && args.NewValue != null)
// setup new tooltip
if (newToolTip != previousToolTip)
{
SetupToolTip(newToolTip);
}
}
else
{
toolTip = new ToolTip { Content = args.NewValue };
var previousTooltip = GetToolTipReference(element);
if (previousTooltip != null)
{
// update the old tooltip with new content
previousTooltip.Content = e.NewValue;
}
else
{
// setup a new tooltip
previousTooltip = new ToolTip { Content = e.NewValue };
SetupToolTip(previousTooltip);
}
}

if (toolTip != null)
void SetupToolTip(ToolTip tooltip)
{
// First time: we're subscribing to event handlers
tooltip.Placement = GetPlacement(tooltip);
tooltip.SetAnchor(GetPlacementTarget(element) ?? element);

long currentHoverId = 0;
SetToolTipReference(element, tooltip);
tooltip._pointerEventSubscriptions = SubscribeToEvents(element, tooltip);
}
void DisposePreviousToolTip(ToolTip tooltip = null)
{
tooltip ??= GetToolTipReference(element);

toolTip.SetAnchor(element);
SetToolTipReference(element, null);
tooltip._pointerEventSubscriptions?.Dispose();
tooltip._pointerEventSubscriptions = null;
}
}

element.Loaded += (snd, evt) =>
{
element.PointerEntered += OnPointerEntered;
element.PointerExited += OnPointerExited;
};
private static void OnPlacementChanged(DependencyObject dependencyobject, DependencyPropertyChangedEventArgs e)
{
if (GetToolTipReference(dependencyobject) is { } tooltip)
{
tooltip.Placement = (PlacementMode)e.NewValue;
}
}

element.Unloaded += (snd, evt) =>
{
toolTip.IsOpen = false;
private static IDisposable SubscribeToEvents(FrameworkElement control, ToolTip tooltip)
{
// event subscriptions
if (control.IsLoaded)
{
SubscribeToPointerEvents(control, null);
}
control.Loaded += SubscribeToPointerEvents;
control.Unloaded += UnsubscribeToPointerEvents;

void SubscribeToPointerEvents(object sender, RoutedEventArgs e)
{
control.PointerEntered += OnPointerEntered;
control.PointerExited += OnPointerExited;
}
void UnsubscribeToPointerEvents(object sender, RoutedEventArgs e)
{
control.PointerEntered -= OnPointerEntered;
control.PointerExited -= OnPointerExited;
}

element.PointerEntered -= OnPointerEntered;
element.PointerExited -= OnPointerExited;
};
return Disposable.Create(() =>
{
control.Loaded -= SubscribeToPointerEvents;
control.Unloaded -= UnsubscribeToPointerEvents;
UnsubscribeToPointerEvents(control, null);
void OnPointerEntered(object snd, PointerRoutedEventArgs evt)
{
var t = HoverTask(++currentHoverId);
}
tooltip.IsOpen = false;
tooltip.CurrentHoverId++;
});

void OnPointerExited(object snd, PointerRoutedEventArgs evt)
// pointer event handlers
async void OnPointerEntered(object snd, PointerRoutedEventArgs evt)
{
await HoverTask(++tooltip.CurrentHoverId).ConfigureAwait(false);
}
void OnPointerExited(object snd, PointerRoutedEventArgs evt)
{
tooltip.CurrentHoverId++;
tooltip.IsOpen = false;
}
async Task HoverTask(long hoverId)
{
await Task.Delay(FeatureConfiguration.ToolTip.ShowDelay).ConfigureAwait(false);
if (tooltip.CurrentHoverId != hoverId)
{
currentHoverId++;
toolTip.IsOpen = false;
return;
}

async Task HoverTask(long hoverId)
if (control.IsLoaded)
{
await Task.Delay(FeatureConfiguration.ToolTip.ShowDelay);
if (currentHoverId != hoverId)
{
return;
}
tooltip.IsOpen = true;

if (element.IsLoaded)
await Task.Delay(FeatureConfiguration.ToolTip.ShowDuration).ConfigureAwait(false);
if (tooltip.CurrentHoverId == hoverId)
{
toolTip.IsOpen = true;
await Task.Delay(FeatureConfiguration.ToolTip.ShowDuration);
if (currentHoverId == hoverId)
{
toolTip.IsOpen = false;
}
tooltip.IsOpen = false;
}
}
}
Expand Down

0 comments on commit 5583919

Please sign in to comment.