ToolTip.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Reactive.Linq;
  5. using Avalonia.Controls.Primitives;
  6. namespace Avalonia.Controls
  7. {
  8. /// <summary>
  9. /// A control which pops up a hint when a control is hovered.
  10. /// </summary>
  11. /// <remarks>
  12. /// You will probably not want to create a <see cref="ToolTip"/> control directly: if added to
  13. /// the tree it will act as a simple <see cref="ContentControl"/> styled to look like a tooltip.
  14. /// To add a tooltip to a control, use the <see cref="TipProperty"/> attached property,
  15. /// assigning the content that you want displayed.
  16. /// </remarks>
  17. public class ToolTip : ContentControl
  18. {
  19. /// <summary>
  20. /// Defines the ToolTip.Tip attached property.
  21. /// </summary>
  22. public static readonly AttachedProperty<object> TipProperty =
  23. AvaloniaProperty.RegisterAttached<ToolTip, Control, object>("Tip");
  24. /// <summary>
  25. /// Defines the ToolTip.IsOpen attached property.
  26. /// </summary>
  27. public static readonly AttachedProperty<bool> IsOpenProperty =
  28. AvaloniaProperty.RegisterAttached<ToolTip, Control, bool>("IsOpen");
  29. /// <summary>
  30. /// Defines the ToolTip.Placement property.
  31. /// </summary>
  32. public static readonly AttachedProperty<PlacementMode> PlacementProperty =
  33. AvaloniaProperty.RegisterAttached<ToolTip, Control, PlacementMode>("Placement", defaultValue: PlacementMode.Pointer);
  34. /// <summary>
  35. /// Defines the ToolTip.HorizontalOffset property.
  36. /// </summary>
  37. public static readonly AttachedProperty<double> HorizontalOffsetProperty =
  38. AvaloniaProperty.RegisterAttached<ToolTip, Control, double>("HorizontalOffset");
  39. /// <summary>
  40. /// Defines the ToolTip.VerticalOffset property.
  41. /// </summary>
  42. public static readonly AttachedProperty<double> VerticalOffsetProperty =
  43. AvaloniaProperty.RegisterAttached<ToolTip, Control, double>("VerticalOffset", 20);
  44. /// <summary>
  45. /// Defines the ToolTip.ShowDelay property.
  46. /// </summary>
  47. public static readonly AttachedProperty<int> ShowDelayProperty =
  48. AvaloniaProperty.RegisterAttached<ToolTip, Control, int>("ShowDelay", 400);
  49. /// <summary>
  50. /// Stores the curernt <see cref="ToolTip"/> instance in the control.
  51. /// </summary>
  52. private static readonly AttachedProperty<ToolTip> ToolTipProperty =
  53. AvaloniaProperty.RegisterAttached<ToolTip, Control, ToolTip>("ToolTip");
  54. private PopupRoot _popup;
  55. /// <summary>
  56. /// Initializes static members of the <see cref="ToolTip"/> class.
  57. /// </summary>
  58. static ToolTip()
  59. {
  60. TipProperty.Changed.Subscribe(ToolTipService.Instance.TipChanged);
  61. IsOpenProperty.Changed.Subscribe(IsOpenChanged);
  62. }
  63. /// <summary>
  64. /// Gets the value of the ToolTip.Tip attached property.
  65. /// </summary>
  66. /// <param name="element">The control to get the property from.</param>
  67. /// <returns>
  68. /// The content to be displayed in the control's tooltip.
  69. /// </returns>
  70. public static object GetTip(Control element)
  71. {
  72. return element.GetValue(TipProperty);
  73. }
  74. /// <summary>
  75. /// Sets the value of the ToolTip.Tip attached property.
  76. /// </summary>
  77. /// <param name="element">The control to get the property from.</param>
  78. /// <param name="value">The content to be displayed in the control's tooltip.</param>
  79. public static void SetTip(Control element, object value)
  80. {
  81. element.SetValue(TipProperty, value);
  82. }
  83. /// <summary>
  84. /// Gets the value of the ToolTip.IsOpen attached property.
  85. /// </summary>
  86. /// <param name="element">The control to get the property from.</param>
  87. /// <returns>
  88. /// A value indicating whether the tool tip is visible.
  89. /// </returns>
  90. public static bool GetIsOpen(Control element)
  91. {
  92. return element.GetValue(IsOpenProperty);
  93. }
  94. /// <summary>
  95. /// Sets the value of the ToolTip.IsOpen attached property.
  96. /// </summary>
  97. /// <param name="element">The control to get the property from.</param>
  98. /// <param name="value">A value indicating whether the tool tip is visible.</param>
  99. public static void SetIsOpen(Control element, bool value)
  100. {
  101. element.SetValue(IsOpenProperty, value);
  102. }
  103. /// <summary>
  104. /// Gets the value of the ToolTip.Placement attached property.
  105. /// </summary>
  106. /// <param name="element">The control to get the property from.</param>
  107. /// <returns>
  108. /// A value indicating how the tool tip is positioned.
  109. /// </returns>
  110. public static PlacementMode GetPlacement(Control element)
  111. {
  112. return element.GetValue(PlacementProperty);
  113. }
  114. /// <summary>
  115. /// Sets the value of the ToolTip.Placement attached property.
  116. /// </summary>
  117. /// <param name="element">The control to get the property from.</param>
  118. /// <param name="value">A value indicating how the tool tip is positioned.</param>
  119. public static void SetPlacement(Control element, PlacementMode value)
  120. {
  121. element.SetValue(PlacementProperty, value);
  122. }
  123. /// <summary>
  124. /// Gets the value of the ToolTip.HorizontalOffset attached property.
  125. /// </summary>
  126. /// <param name="element">The control to get the property from.</param>
  127. /// <returns>
  128. /// A value indicating how the tool tip is positioned.
  129. /// </returns>
  130. public static double GetHorizontalOffset(Control element)
  131. {
  132. return element.GetValue(HorizontalOffsetProperty);
  133. }
  134. /// <summary>
  135. /// Sets the value of the ToolTip.HorizontalOffset attached property.
  136. /// </summary>
  137. /// <param name="element">The control to get the property from.</param>
  138. /// <param name="value">A value indicating how the tool tip is positioned.</param>
  139. public static void SetHorizontalOffset(Control element, double value)
  140. {
  141. element.SetValue(HorizontalOffsetProperty, value);
  142. }
  143. /// <summary>
  144. /// Gets the value of the ToolTip.VerticalOffset attached property.
  145. /// </summary>
  146. /// <param name="element">The control to get the property from.</param>
  147. /// <returns>
  148. /// A value indicating how the tool tip is positioned.
  149. /// </returns>
  150. public static double GetVerticalOffset(Control element)
  151. {
  152. return element.GetValue(VerticalOffsetProperty);
  153. }
  154. /// <summary>
  155. /// Sets the value of the ToolTip.VerticalOffset attached property.
  156. /// </summary>
  157. /// <param name="element">The control to get the property from.</param>
  158. /// <param name="value">A value indicating how the tool tip is positioned.</param>
  159. public static void SetVerticalOffset(Control element, double value)
  160. {
  161. element.SetValue(VerticalOffsetProperty, value);
  162. }
  163. /// <summary>
  164. /// Gets the value of the ToolTip.ShowDelay attached property.
  165. /// </summary>
  166. /// <param name="element">The control to get the property from.</param>
  167. /// <returns>
  168. /// A value indicating the time, in milliseconds, before a tool tip opens.
  169. /// </returns>
  170. public static int GetShowDelay(Control element)
  171. {
  172. return element.GetValue(ShowDelayProperty);
  173. }
  174. /// <summary>
  175. /// Sets the value of the ToolTip.ShowDelay attached property.
  176. /// </summary>
  177. /// <param name="element">The control to get the property from.</param>
  178. /// <param name="value">A value indicating the time, in milliseconds, before a tool tip opens.</param>
  179. public static void SetShowDelay(Control element, int value)
  180. {
  181. element.SetValue(ShowDelayProperty, value);
  182. }
  183. private static void IsOpenChanged(AvaloniaPropertyChangedEventArgs e)
  184. {
  185. var control = (Control)e.Sender;
  186. if ((bool)e.NewValue)
  187. {
  188. var tip = GetTip(control);
  189. if (tip == null) return;
  190. var toolTip = control.GetValue(ToolTipProperty);
  191. if (toolTip == null || (tip != toolTip && tip != toolTip.Content))
  192. {
  193. toolTip?.Close();
  194. toolTip = tip as ToolTip ?? new ToolTip { Content = tip };
  195. control.SetValue(ToolTipProperty, toolTip);
  196. }
  197. toolTip.Open(control);
  198. }
  199. else
  200. {
  201. var toolTip = control.GetValue(ToolTipProperty);
  202. toolTip?.Close();
  203. }
  204. }
  205. private void Open(Control control)
  206. {
  207. Close();
  208. _popup = new PopupRoot { Content = this, };
  209. ((ISetLogicalParent)_popup).SetParent(control);
  210. _popup.Position = Popup.GetPosition(control, GetPlacement(control), _popup,
  211. GetHorizontalOffset(control), GetVerticalOffset(control));
  212. _popup.Show();
  213. _popup.SnapInsideScreenEdges();
  214. }
  215. private void Close()
  216. {
  217. if (_popup != null)
  218. {
  219. _popup.Content = null;
  220. _popup.Hide();
  221. _popup = null;
  222. }
  223. }
  224. }
  225. }